mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
Merge branch 'stretch-unstable' into nodejs_helper
This commit is contained in:
commit
34d19df5cd
65 changed files with 3818 additions and 2506 deletions
|
@ -92,3 +92,10 @@ test-user-group:
|
||||||
script:
|
script:
|
||||||
- cd src/yunohost
|
- cd src/yunohost
|
||||||
- py.test tests/test_user-group.py
|
- py.test tests/test_user-group.py
|
||||||
|
|
||||||
|
test-regenconf:
|
||||||
|
extends: .tests
|
||||||
|
stage: tests
|
||||||
|
script:
|
||||||
|
- cd src/yunohost
|
||||||
|
- py.test tests/test_regenconf.py
|
||||||
|
|
|
@ -406,6 +406,10 @@ domain:
|
||||||
list:
|
list:
|
||||||
action_help: List domains
|
action_help: List domains
|
||||||
api: GET /domains
|
api: GET /domains
|
||||||
|
arguments:
|
||||||
|
--exclude-subdomains:
|
||||||
|
help: Filter out domains that are obviously subdomains of other declared domains
|
||||||
|
action: store_true
|
||||||
|
|
||||||
### domain_add()
|
### domain_add()
|
||||||
add:
|
add:
|
||||||
|
@ -563,6 +567,9 @@ app:
|
||||||
help: Also return a list of app categories
|
help: Also return a list of app categories
|
||||||
action: store_true
|
action: store_true
|
||||||
|
|
||||||
|
fetchlist:
|
||||||
|
deprecated: true
|
||||||
|
|
||||||
### app_list()
|
### app_list()
|
||||||
list:
|
list:
|
||||||
action_help: List installed apps
|
action_help: List installed apps
|
||||||
|
@ -572,6 +579,12 @@ app:
|
||||||
full: --full
|
full: --full
|
||||||
help: Display all details, including the app manifest and various other infos
|
help: Display all details, including the app manifest and various other infos
|
||||||
action: store_true
|
action: store_true
|
||||||
|
-i:
|
||||||
|
full: --installed
|
||||||
|
help: Dummy argument, does nothing anymore (still there only for backward compatibility)
|
||||||
|
action: store_true
|
||||||
|
filter:
|
||||||
|
nargs: '?'
|
||||||
|
|
||||||
### app_info()
|
### app_info()
|
||||||
info:
|
info:
|
||||||
|
@ -1041,6 +1054,7 @@ service:
|
||||||
### service_restart()
|
### service_restart()
|
||||||
restart:
|
restart:
|
||||||
action_help: Restart one or more services. If the services are not running yet, they will be started.
|
action_help: Restart one or more services. If the services are not running yet, they will be started.
|
||||||
|
api: PUT /services/<names>/restart
|
||||||
arguments:
|
arguments:
|
||||||
names:
|
names:
|
||||||
help: Service name to restart
|
help: Service name to restart
|
||||||
|
@ -1676,7 +1690,7 @@ diagnosis:
|
||||||
action: store_true
|
action: store_true
|
||||||
|
|
||||||
run:
|
run:
|
||||||
action_help: Show most recents diagnosis results
|
action_help: Run diagnosis
|
||||||
api: POST /diagnosis/run
|
api: POST /diagnosis/run
|
||||||
arguments:
|
arguments:
|
||||||
categories:
|
categories:
|
||||||
|
@ -1685,6 +1699,9 @@ diagnosis:
|
||||||
--force:
|
--force:
|
||||||
help: Ignore the cached report even if it is still 'fresh'
|
help: Ignore the cached report even if it is still 'fresh'
|
||||||
action: store_true
|
action: store_true
|
||||||
|
--except-if-never-ran-yet:
|
||||||
|
help: Don't run anything if diagnosis never ran yet ... (this is meant to be used by the webadmin)
|
||||||
|
action: store_true
|
||||||
|
|
||||||
ignore:
|
ignore:
|
||||||
action_help: Configure some diagnosis results to be ignored and therefore not considered as actual issues
|
action_help: Configure some diagnosis results to be ignored and therefore not considered as actual issues
|
||||||
|
@ -1701,3 +1718,14 @@ diagnosis:
|
||||||
--list:
|
--list:
|
||||||
help: List active ignore filters
|
help: List active ignore filters
|
||||||
action: store_true
|
action: store_true
|
||||||
|
|
||||||
|
get:
|
||||||
|
action_help: Low-level command to fetch raw data and status about a specific diagnosis test
|
||||||
|
api: GET /diagnosis/item/<category>
|
||||||
|
arguments:
|
||||||
|
category:
|
||||||
|
help: Diagnosis category to fetch results from
|
||||||
|
item:
|
||||||
|
help: "List of criteria describing the test. Must correspond exactly to the 'meta' infos in 'yunohost diagnosis show'"
|
||||||
|
metavar: CRITERIA
|
||||||
|
nargs: "*"
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
# usage: ynh_wait_dpkg_free
|
# usage: ynh_wait_dpkg_free
|
||||||
|
# | exit: Return 1 if dpkg is broken
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.3.1 or higher.
|
# Requires YunoHost version 3.3.1 or higher.
|
||||||
ynh_wait_dpkg_free() {
|
ynh_wait_dpkg_free() {
|
||||||
|
@ -27,7 +28,7 @@ ynh_wait_dpkg_free() {
|
||||||
while read dpkg_file <&9
|
while read dpkg_file <&9
|
||||||
do
|
do
|
||||||
# Check if the name of this file contains only numbers.
|
# Check if the name of this file contains only numbers.
|
||||||
if echo "$dpkg_file" | grep -Pq "^[[:digit:]]+$"
|
if echo "$dpkg_file" | grep --perl-regexp --quiet "^[[:digit:]]+$"
|
||||||
then
|
then
|
||||||
# If so, that a remaining of dpkg.
|
# If so, that a remaining of dpkg.
|
||||||
ynh_print_err "E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem."
|
ynh_print_err "E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem."
|
||||||
|
@ -45,20 +46,20 @@ ynh_wait_dpkg_free() {
|
||||||
# example: ynh_package_is_installed --package=yunohost && echo "ok"
|
# example: ynh_package_is_installed --package=yunohost && echo "ok"
|
||||||
#
|
#
|
||||||
# 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.
|
# 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
|
||||||
declare -Ar args_array=( [p]=package= )
|
local -A args_array=( [p]=package= )
|
||||||
local package
|
local package
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
ynh_wait_dpkg_free
|
ynh_wait_dpkg_free
|
||||||
dpkg-query -W -f '${Status}' "$package" 2>/dev/null \
|
dpkg-query --show --showformat='${Status}' "$package" 2>/dev/null \
|
||||||
| grep -c "ok installed" &>/dev/null
|
| grep --count "ok installed" &>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get the version of an installed package
|
# Get the version of an installed package
|
||||||
|
@ -66,20 +67,21 @@ ynh_package_is_installed() {
|
||||||
# example: version=$(ynh_package_version --package=yunohost)
|
# example: version=$(ynh_package_version --package=yunohost)
|
||||||
#
|
#
|
||||||
# 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.
|
# 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
|
||||||
declare -Ar args_array=( [p]=package= )
|
local -A args_array=( [p]=package= )
|
||||||
local package
|
local package
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
if ynh_package_is_installed "$package"; then
|
if ynh_package_is_installed "$package"
|
||||||
dpkg-query -W -f '${Version}' "$package" 2>/dev/null
|
then
|
||||||
|
dpkg-query --show --showformat='${Version}' "$package" 2>/dev/null
|
||||||
else
|
else
|
||||||
echo ''
|
echo ''
|
||||||
fi
|
fi
|
||||||
|
@ -94,7 +96,7 @@ ynh_package_version() {
|
||||||
# Requires YunoHost version 2.4.0.3 or higher.
|
# Requires YunoHost version 2.4.0.3 or higher.
|
||||||
ynh_apt() {
|
ynh_apt() {
|
||||||
ynh_wait_dpkg_free
|
ynh_wait_dpkg_free
|
||||||
LC_ALL=C DEBIAN_FRONTEND=noninteractive apt-get -y $@
|
LC_ALL=C DEBIAN_FRONTEND=noninteractive apt-get --assume-yes $@
|
||||||
}
|
}
|
||||||
|
|
||||||
# Update package index files
|
# Update package index files
|
||||||
|
@ -113,8 +115,8 @@ ynh_package_update() {
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.2.4 or higher.
|
# 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 --option Dpkg::Options::=--force-confdef \
|
||||||
-o Dpkg::Options::=--force-confold install $@
|
--option Dpkg::Options::=--force-confold install $@
|
||||||
}
|
}
|
||||||
|
|
||||||
# Remove package(s)
|
# Remove package(s)
|
||||||
|
@ -163,8 +165,8 @@ ynh_package_install_from_equivs () {
|
||||||
local controlfile=$1
|
local controlfile=$1
|
||||||
|
|
||||||
# retrieve package information
|
# retrieve package information
|
||||||
local pkgname=$(grep '^Package: ' $controlfile | cut -d' ' -f 2) # Retrieve the name of the debian package
|
local pkgname=$(grep '^Package: ' $controlfile | cut --delimiter=' ' --fields=2) # Retrieve the name of the debian package
|
||||||
local pkgversion=$(grep '^Version: ' $controlfile | cut -d' ' -f 2) # And its version number
|
local pkgversion=$(grep '^Version: ' $controlfile | cut --delimiter=' ' --fields=2) # And its version number
|
||||||
[[ -z "$pkgname" || -z "$pkgversion" ]] \
|
[[ -z "$pkgname" || -z "$pkgversion" ]] \
|
||||||
&& ynh_die --message="Invalid control file" # Check if this 2 variables aren't empty.
|
&& ynh_die --message="Invalid control file" # Check if this 2 variables aren't empty.
|
||||||
|
|
||||||
|
@ -172,7 +174,7 @@ ynh_package_install_from_equivs () {
|
||||||
ynh_package_update
|
ynh_package_update
|
||||||
|
|
||||||
# Build and install the package
|
# Build and install the package
|
||||||
local TMPDIR=$(mktemp -d)
|
local TMPDIR=$(mktemp --directory)
|
||||||
|
|
||||||
# Force the compatibility level at 10, levels below are deprecated
|
# Force the compatibility level at 10, levels below are deprecated
|
||||||
echo 10 > /usr/share/equivs/template/debian/compat
|
echo 10 > /usr/share/equivs/template/debian/compat
|
||||||
|
@ -185,21 +187,21 @@ ynh_package_install_from_equivs () {
|
||||||
cp "$controlfile" "${TMPDIR}/control"
|
cp "$controlfile" "${TMPDIR}/control"
|
||||||
(cd "$TMPDIR"
|
(cd "$TMPDIR"
|
||||||
LC_ALL=C equivs-build ./control 1> /dev/null
|
LC_ALL=C equivs-build ./control 1> /dev/null
|
||||||
dpkg --force-depends -i "./${pkgname}_${pkgversion}_all.deb" 2>&1)
|
dpkg --force-depends --install "./${pkgname}_${pkgversion}_all.deb" 2>&1)
|
||||||
# If install fails we use "apt-get check" to try to debug and diagnose possible unmet dependencies
|
# If install fails we use "apt-get check" to try to debug and diagnose possible unmet dependencies
|
||||||
# Note the use of { } which allows to group commands without starting a subshell (otherwise the ynh_die wouldn't exit the current shell).
|
# Note the use of { } which allows to group commands without starting a subshell (otherwise the ynh_die wouldn't exit the current shell).
|
||||||
# Be careful with the syntax : the semicolon + space at the end is important!
|
# Be careful with the syntax : the semicolon + space at the end is important!
|
||||||
|
|
||||||
ynh_package_install -f || \
|
ynh_package_install --fix-broken || \
|
||||||
{ # If the installation failed
|
{ # If the installation failed
|
||||||
# Get the list of dependencies from the deb
|
# Get the list of dependencies from the deb
|
||||||
local dependencies="$(dpkg --info "$TMPDIR/${pkgname}_${pkgversion}_all.deb" | grep Depends | \
|
local dependencies="$(dpkg --info "$TMPDIR/${pkgname}_${pkgversion}_all.deb" | grep Depends | \
|
||||||
sed 's/^ Depends: //' | sed 's/,//g')"
|
sed 's/^ Depends: //' | sed 's/,//g')"
|
||||||
# Fake an install of those dependencies to see the errors
|
# Fake an install of those dependencies to see the errors
|
||||||
# The sed command here is, Print only from '--fix-broken' to the end.
|
# The sed command here is, Print only from '--fix-broken' to the end.
|
||||||
ynh_package_install $dependencies --dry-run | sed -n '/--fix-broken/,$p' >&2
|
ynh_package_install $dependencies --dry-run | sed --quiet '/--fix-broken/,$p' >&2
|
||||||
ynh_die --message="Unable to install dependencies"; }
|
ynh_die --message="Unable to install dependencies"; }
|
||||||
[[ -n "$TMPDIR" ]] && rm -rf $TMPDIR # Remove the temp dir.
|
[[ -n "$TMPDIR" ]] && rm --recursive --force $TMPDIR # Remove the temp dir.
|
||||||
|
|
||||||
# check if the package is actually installed
|
# check if the package is actually installed
|
||||||
ynh_package_is_installed "$pkgname"
|
ynh_package_is_installed "$pkgname"
|
||||||
|
@ -225,7 +227,7 @@ ynh_install_app_dependencies () {
|
||||||
manifest_path="../settings/manifest.json" # Into the restore script, the manifest is not at the same place
|
manifest_path="../settings/manifest.json" # Into the restore script, the manifest is not at the same place
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local version=$(grep '\"version\": ' "$manifest_path" | cut -d '"' -f 4) # Retrieve the version number in the manifest file.
|
local version=$(grep '\"version\": ' "$manifest_path" | cut --delimiter='"' --fields=4) # Retrieve the version number in the manifest file.
|
||||||
if [ ${#version} -eq 0 ]; then
|
if [ ${#version} -eq 0 ]; then
|
||||||
version="1.0"
|
version="1.0"
|
||||||
fi
|
fi
|
||||||
|
@ -251,16 +253,16 @@ ynh_install_app_dependencies () {
|
||||||
# https://github.com/YunoHost/issues/issues/1407
|
# https://github.com/YunoHost/issues/issues/1407
|
||||||
#
|
#
|
||||||
# If we require to install php dependency
|
# If we require to install php dependency
|
||||||
if echo $dependencies | grep -q 'php';
|
if echo $dependencies | grep --quiet 'php'
|
||||||
then
|
then
|
||||||
# And we have packages from sury installed (7.0.33-10+weirdshiftafter instead of 7.0.33-0 on debian)
|
# And we have packages from sury installed (7.0.33-10+weirdshiftafter instead of 7.0.33-0 on debian)
|
||||||
if dpkg --list | grep "php7.0" | grep -q -v "7.0.33-0+deb9"
|
if dpkg --list | grep "php7.0" | grep --quiet --invert-match "7.0.33-0+deb9"
|
||||||
then
|
then
|
||||||
# And sury ain't already installed
|
# And sury ain't already installed
|
||||||
if ! grep -nrq "sury" /etc/apt/sources.list*
|
if ! grep --line-number --recursive --quiet "sury" /etc/apt/sources.list*
|
||||||
then
|
then
|
||||||
# Re-add sury
|
# Re-add sury
|
||||||
ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(lsb_release -sc) main" --key="https://packages.sury.org/php/apt.gpg" --name=extra_php_version
|
ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(ynh_get_debian_release) main" --key="https://packages.sury.org/php/apt.gpg" --name=extra_php_version
|
||||||
|
|
||||||
# Pin this sury repository to prevent sury of doing shit
|
# Pin this sury repository to prevent sury of doing shit
|
||||||
ynh_pin_repo --package="*" --pin="origin \"packages.sury.org\"" --priority=200 --name=extra_php_version
|
ynh_pin_repo --package="*" --pin="origin \"packages.sury.org\"" --priority=200 --name=extra_php_version
|
||||||
|
@ -287,15 +289,15 @@ EOF
|
||||||
|
|
||||||
# Add dependencies to install with ynh_install_app_dependencies
|
# Add dependencies to install with ynh_install_app_dependencies
|
||||||
#
|
#
|
||||||
# [internal]
|
|
||||||
#
|
|
||||||
# usage: ynh_add_app_dependencies --package=phpversion [--replace]
|
# usage: ynh_add_app_dependencies --package=phpversion [--replace]
|
||||||
# | arg: -p, --package - Packages to add as dependencies for the app.
|
# | arg: -p, --package= - Packages to add as dependencies for the app.
|
||||||
# | arg: -r, --replace - Replace dependencies instead of adding to existing ones.
|
# | arg: -r, --replace - Replace dependencies instead of adding to existing ones.
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_add_app_dependencies () {
|
ynh_add_app_dependencies () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=pr
|
local legacy_args=pr
|
||||||
declare -Ar args_array=( [p]=package= [r]=replace)
|
local -A args_array=( [p]=package= [r]=replace)
|
||||||
local package
|
local package
|
||||||
local replace
|
local replace
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -334,14 +336,16 @@ ynh_remove_app_dependencies () {
|
||||||
# Install packages from an extra repository properly.
|
# Install packages from an extra repository properly.
|
||||||
#
|
#
|
||||||
# usage: ynh_install_extra_app_dependencies --repo="repo" --package="dep1 dep2" [--key=key_url] [--name=name]
|
# usage: ynh_install_extra_app_dependencies --repo="repo" --package="dep1 dep2" [--key=key_url] [--name=name]
|
||||||
# | arg: -r, --repo - Complete url of the extra repository.
|
# | arg: -r, --repo= - Complete url of the extra repository.
|
||||||
# | arg: -p, --package - The packages to install from this extra repository
|
# | arg: -p, --package= - The packages to install from this extra repository
|
||||||
# | arg: -k, --key - url to get the public key.
|
# | arg: -k, --key= - url to get the public key.
|
||||||
# | arg: -n, --name - Name for the files for this repo, $app as default value.
|
# | arg: -n, --name= - Name for the files for this repo, $app as default value.
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_install_extra_app_dependencies () {
|
ynh_install_extra_app_dependencies () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=rpkn
|
local legacy_args=rpkn
|
||||||
declare -Ar args_array=( [r]=repo= [p]=package= [k]=key= [n]=name= )
|
local -A args_array=( [r]=repo= [p]=package= [k]=key= [n]=name= )
|
||||||
local repo
|
local repo
|
||||||
local package
|
local package
|
||||||
local key
|
local key
|
||||||
|
@ -371,15 +375,17 @@ ynh_install_extra_app_dependencies () {
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
# usage: ynh_install_extra_repo --repo="repo" [--key=key_url] [--priority=priority_value] [--name=name] [--append]
|
# usage: ynh_install_extra_repo --repo="repo" [--key=key_url] [--priority=priority_value] [--name=name] [--append]
|
||||||
# | arg: -r, --repo - Complete url of the extra repository.
|
# | arg: -r, --repo= - Complete url of the extra repository.
|
||||||
# | arg: -k, --key - url to get the public key.
|
# | arg: -k, --key= - url to get the public key.
|
||||||
# | arg: -p, --priority - Priority for the pin
|
# | arg: -p, --priority= - Priority for the pin
|
||||||
# | arg: -n, --name - Name for the files for this repo, $app as default value.
|
# | arg: -n, --name= - Name for the files for this repo, $app as default value.
|
||||||
# | arg: -a, --append - Do not overwrite existing files.
|
# | arg: -a, --append - Do not overwrite existing files.
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_install_extra_repo () {
|
ynh_install_extra_repo () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=rkpna
|
local legacy_args=rkpna
|
||||||
declare -Ar args_array=( [r]=repo= [k]=key= [p]=priority= [n]=name= [a]=append )
|
local -A args_array=( [r]=repo= [k]=key= [p]=priority= [n]=name= [a]=append )
|
||||||
local repo
|
local repo
|
||||||
local key
|
local key
|
||||||
local priority
|
local priority
|
||||||
|
@ -395,7 +401,7 @@ ynh_install_extra_repo () {
|
||||||
if [ $append -eq 1 ]
|
if [ $append -eq 1 ]
|
||||||
then
|
then
|
||||||
append="--append"
|
append="--append"
|
||||||
wget_append="tee -a"
|
wget_append="tee --append"
|
||||||
else
|
else
|
||||||
append=""
|
append=""
|
||||||
wget_append="tee"
|
wget_append="tee"
|
||||||
|
@ -431,8 +437,8 @@ ynh_install_extra_repo () {
|
||||||
# Get the public key for the repo
|
# Get the public key for the repo
|
||||||
if [ -n "$key" ]
|
if [ -n "$key" ]
|
||||||
then
|
then
|
||||||
mkdir -p "/etc/apt/trusted.gpg.d"
|
mkdir --parents "/etc/apt/trusted.gpg.d"
|
||||||
wget -q "$key" -O - | gpg --dearmor | $wget_append /etc/apt/trusted.gpg.d/$name.gpg > /dev/null
|
wget --quiet "$key" --output-document=- | gpg --dearmor | $wget_append /etc/apt/trusted.gpg.d/$name.gpg > /dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Update the list of package with the new repo
|
# Update the list of package with the new repo
|
||||||
|
@ -444,11 +450,13 @@ ynh_install_extra_repo () {
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
# usage: ynh_remove_extra_repo [--name=name]
|
# usage: ynh_remove_extra_repo [--name=name]
|
||||||
# | arg: -n, --name - Name for the files for this repo, $app as default value.
|
# | arg: -n, --name= - Name for the files for this repo, $app as default value.
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_remove_extra_repo () {
|
ynh_remove_extra_repo () {
|
||||||
# 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
|
||||||
declare -Ar args_array=( [n]=name= )
|
local -A args_array=( [n]=name= )
|
||||||
local name
|
local name
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -468,20 +476,21 @@ ynh_remove_extra_repo () {
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
# usage: ynh_add_repo --uri=uri --suite=suite --component=component [--name=name] [--append]
|
# usage: ynh_add_repo --uri=uri --suite=suite --component=component [--name=name] [--append]
|
||||||
# | arg: -u, --uri - Uri of the repository.
|
# | arg: -u, --uri= - Uri of the repository.
|
||||||
# | arg: -s, --suite - Suite of the repository.
|
# | arg: -s, --suite= - Suite of the repository.
|
||||||
# | arg: -c, --component - Component of the repository.
|
# | arg: -c, --component= - Component of the repository.
|
||||||
# | arg: -n, --name - Name for the files for this repo, $app as default value.
|
# | arg: -n, --name= - Name for the files for this repo, $app as default value.
|
||||||
# | arg: -a, --append - Do not overwrite existing files.
|
# | arg: -a, --append - Do not overwrite existing files.
|
||||||
#
|
#
|
||||||
# Example for a repo like deb http://forge.yunohost.org/debian/ stretch stable
|
# Example for a repo like deb http://forge.yunohost.org/debian/ stretch stable
|
||||||
# uri suite component
|
# uri suite component
|
||||||
# ynh_add_repo --uri=http://forge.yunohost.org/debian/ --suite=stretch --component=stable
|
# ynh_add_repo --uri=http://forge.yunohost.org/debian/ --suite=stretch --component=stable
|
||||||
#
|
#
|
||||||
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_add_repo () {
|
ynh_add_repo () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=uscna
|
local legacy_args=uscna
|
||||||
declare -Ar args_array=( [u]=uri= [s]=suite= [c]=component= [n]=name= [a]=append )
|
local -A args_array=( [u]=uri= [s]=suite= [c]=component= [n]=name= [a]=append )
|
||||||
local uri
|
local uri
|
||||||
local suite
|
local suite
|
||||||
local component
|
local component
|
||||||
|
@ -494,12 +503,12 @@ ynh_add_repo () {
|
||||||
|
|
||||||
if [ $append -eq 1 ]
|
if [ $append -eq 1 ]
|
||||||
then
|
then
|
||||||
append="tee -a"
|
append="tee --append"
|
||||||
else
|
else
|
||||||
append="tee"
|
append="tee"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "/etc/apt/sources.list.d"
|
mkdir --parents "/etc/apt/sources.list.d"
|
||||||
# Add the new repo in sources.list.d
|
# Add the new repo in sources.list.d
|
||||||
echo "deb $uri $suite $component" \
|
echo "deb $uri $suite $component" \
|
||||||
| $append "/etc/apt/sources.list.d/$name.list"
|
| $append "/etc/apt/sources.list.d/$name.list"
|
||||||
|
@ -510,18 +519,19 @@ ynh_add_repo () {
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
# usage: ynh_pin_repo --package=packages --pin=pin_filter [--priority=priority_value] [--name=name] [--append]
|
# usage: ynh_pin_repo --package=packages --pin=pin_filter [--priority=priority_value] [--name=name] [--append]
|
||||||
# | arg: -p, --package - Packages concerned by the pin. Or all, *.
|
# | arg: -p, --package= - Packages concerned by the pin. Or all, *.
|
||||||
# | arg: -i, --pin - Filter for the pin.
|
# | arg: -i, --pin= - Filter for the pin.
|
||||||
# | arg: -p, --priority - Priority for the pin
|
# | arg: -p, --priority= - Priority for the pin
|
||||||
# | arg: -n, --name - Name for the files for this repo, $app as default value.
|
# | arg: -n, --name= - Name for the files for this repo, $app as default value.
|
||||||
# | arg: -a, --append - Do not overwrite existing files.
|
# | arg: -a, --append - Do not overwrite existing files.
|
||||||
#
|
#
|
||||||
# See https://manpages.debian.org/stretch/apt/apt_preferences.5.en.html#How_APT_Interprets_Priorities for information about pinning.
|
# See https://manpages.debian.org/stretch/apt/apt_preferences.5.en.html#How_APT_Interprets_Priorities for information about pinning.
|
||||||
#
|
#
|
||||||
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_pin_repo () {
|
ynh_pin_repo () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=pirna
|
local legacy_args=pirna
|
||||||
declare -Ar args_array=( [p]=package= [i]=pin= [r]=priority= [n]=name= [a]=append )
|
local -A args_array=( [p]=package= [i]=pin= [r]=priority= [n]=name= [a]=append )
|
||||||
local package
|
local package
|
||||||
local pin
|
local pin
|
||||||
local priority
|
local priority
|
||||||
|
@ -536,12 +546,12 @@ ynh_pin_repo () {
|
||||||
|
|
||||||
if [ $append -eq 1 ]
|
if [ $append -eq 1 ]
|
||||||
then
|
then
|
||||||
append="tee -a"
|
append="tee --append"
|
||||||
else
|
else
|
||||||
append="tee"
|
append="tee"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "/etc/apt/preferences.d"
|
mkdir --parents "/etc/apt/preferences.d"
|
||||||
echo "Package: $package
|
echo "Package: $package
|
||||||
Pin: $pin
|
Pin: $pin
|
||||||
Pin-Priority: $priority
|
Pin-Priority: $priority
|
||||||
|
|
|
@ -4,6 +4,13 @@ CAN_BIND=${CAN_BIND:-1}
|
||||||
|
|
||||||
# Add a file or a directory to the list of paths to backup
|
# Add a file or a directory to the list of paths to backup
|
||||||
#
|
#
|
||||||
|
# usage: ynh_backup --src_path=src_path [--dest_path=dest_path] [--is_big] [--not_mandatory]
|
||||||
|
# | arg: -s, --src_path= - file or directory to bind or symlink or copy. it shouldn't be in the backup dir.
|
||||||
|
# | arg: -d, --dest_path= - destination file or directory inside the backup dir
|
||||||
|
# | arg: -b, --is_big - Indicate data are big (mail, video, image ...)
|
||||||
|
# | arg: -m, --not_mandatory - Indicate that if the file is missing, the backup can ignore it.
|
||||||
|
# | arg: arg - Deprecated arg
|
||||||
|
#
|
||||||
# This helper can be used both in a system backup hook, and in an app backup script
|
# This helper can be used both in a system backup hook, and in an app backup script
|
||||||
#
|
#
|
||||||
# Details: ynh_backup writes SRC and the relative DEST into a CSV file. And it
|
# Details: ynh_backup writes SRC and the relative DEST into a CSV file. And it
|
||||||
|
@ -11,13 +18,6 @@ CAN_BIND=${CAN_BIND:-1}
|
||||||
#
|
#
|
||||||
# If DEST is ended by a slash it complete this path with the basename of SRC.
|
# If DEST is ended by a slash it complete this path with the basename of SRC.
|
||||||
#
|
#
|
||||||
# usage: ynh_backup --src_path=src_path [--dest_path=dest_path] [--is_big] [--not_mandatory]
|
|
||||||
# | arg: -s, --src_path - file or directory to bind or symlink or copy. it shouldn't be in the backup dir.
|
|
||||||
# | arg: -d, --dest_path - destination file or directory inside the backup dir
|
|
||||||
# | arg: -b, --is_big - Indicate data are big (mail, video, image ...)
|
|
||||||
# | arg: -m, --not_mandatory - Indicate that if the file is missing, the backup can ignore it.
|
|
||||||
# | arg: arg - Deprecated arg
|
|
||||||
#
|
|
||||||
# Example in the context of a wordpress app
|
# Example in the context of a wordpress app
|
||||||
#
|
#
|
||||||
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf"
|
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf"
|
||||||
|
@ -41,21 +41,22 @@ CAN_BIND=${CAN_BIND:-1}
|
||||||
# # => "/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.
|
# Requires YunoHost version 2.4.0 or higher.
|
||||||
|
# Requires YunoHost version 3.5.0 or higher for the argument --not_mandatory
|
||||||
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 !
|
||||||
|
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=sdbm
|
local legacy_args=sdbm
|
||||||
declare -Ar args_array=( [s]=src_path= [d]=dest_path= [b]=is_big [m]=not_mandatory )
|
local -A args_array=( [s]=src_path= [d]=dest_path= [b]=is_big [m]=not_mandatory )
|
||||||
local src_path
|
local src_path
|
||||||
local dest_path
|
local dest_path
|
||||||
local is_big
|
local is_big
|
||||||
local not_mandatory
|
local not_mandatory
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
local dest_path="${dest_path:-}"
|
dest_path="${dest_path:-}"
|
||||||
local is_big="${is_big:-0}"
|
is_big="${is_big:-0}"
|
||||||
local not_mandatory="${not_mandatory:-0}"
|
not_mandatory="${not_mandatory:-0}"
|
||||||
|
|
||||||
BACKUP_CORE_ONLY=${BACKUP_CORE_ONLY:-0}
|
BACKUP_CORE_ONLY=${BACKUP_CORE_ONLY:-0}
|
||||||
test -n "${app:-}" && do_not_backup_data=$(ynh_app_setting_get --app=$app --key=do_not_backup_data)
|
test -n "${app:-}" && do_not_backup_data=$(ynh_app_setting_get --app=$app --key=do_not_backup_data)
|
||||||
|
@ -64,7 +65,8 @@ ynh_backup() {
|
||||||
# don't backup big data items
|
# don't backup big data items
|
||||||
if [ $is_big -eq 1 ] && ( [ ${do_not_backup_data:-0} -eq 1 ] || [ $BACKUP_CORE_ONLY -eq 1 ] )
|
if [ $is_big -eq 1 ] && ( [ ${do_not_backup_data:-0} -eq 1 ] || [ $BACKUP_CORE_ONLY -eq 1 ] )
|
||||||
then
|
then
|
||||||
if [ $BACKUP_CORE_ONLY -eq 1 ]; then
|
if [ $BACKUP_CORE_ONLY -eq 1 ]
|
||||||
|
then
|
||||||
ynh_print_warn --message="$src_path will not be saved, because 'BACKUP_CORE_ONLY' is set."
|
ynh_print_warn --message="$src_path will not be saved, because 'BACKUP_CORE_ONLY' is set."
|
||||||
else
|
else
|
||||||
ynh_print_warn --message="$src_path will not be saved, because 'do_not_backup_data' is set."
|
ynh_print_warn --message="$src_path will not be saved, because 'do_not_backup_data' is set."
|
||||||
|
@ -76,7 +78,8 @@ ynh_backup() {
|
||||||
# Format correctly source and destination paths
|
# Format correctly source and destination paths
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# Be sure the source path is not empty
|
# Be sure the source path is not empty
|
||||||
[[ -e "${src_path}" ]] || {
|
if [ ! -e "$src_path" ]
|
||||||
|
then
|
||||||
ynh_print_warn --message="Source path '${src_path}' does not exist"
|
ynh_print_warn --message="Source path '${src_path}' does not exist"
|
||||||
if [ "$not_mandatory" == "0" ]
|
if [ "$not_mandatory" == "0" ]
|
||||||
then
|
then
|
||||||
|
@ -91,7 +94,7 @@ ynh_backup() {
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
}
|
fi
|
||||||
|
|
||||||
# Transform the source path as an absolute path
|
# Transform the source path as an absolute path
|
||||||
# If it's a dir remove the ending /
|
# If it's a dir remove the ending /
|
||||||
|
@ -100,12 +103,13 @@ ynh_backup() {
|
||||||
# If there is no destination path, initialize it with the source path
|
# If there is no destination path, initialize it with the source path
|
||||||
# relative to "/".
|
# relative to "/".
|
||||||
# eg: src_path=/etc/yunohost -> dest_path=etc/yunohost
|
# eg: src_path=/etc/yunohost -> dest_path=etc/yunohost
|
||||||
if [[ -z "$dest_path" ]]; then
|
if [[ -z "$dest_path" ]]
|
||||||
|
then
|
||||||
dest_path="${src_path#/}"
|
dest_path="${src_path#/}"
|
||||||
|
|
||||||
else
|
else
|
||||||
if [[ "${dest_path:0:1}" == "/" ]]; then
|
if [[ "${dest_path:0:1}" == "/" ]]
|
||||||
|
then
|
||||||
|
|
||||||
# If the destination path is an absolute path, transform it as a path
|
# If the destination path is an absolute path, transform it as a path
|
||||||
# relative to the current working directory ($YNH_CWD)
|
# relative to the current working directory ($YNH_CWD)
|
||||||
|
@ -117,20 +121,23 @@ ynh_backup() {
|
||||||
dest_path="${dest_path#$YNH_CWD/}"
|
dest_path="${dest_path#$YNH_CWD/}"
|
||||||
|
|
||||||
# Case where $2 is an absolute dir but doesn't begin with $YNH_CWD
|
# Case where $2 is an absolute dir but doesn't begin with $YNH_CWD
|
||||||
[[ "${dest_path:0:1}" == "/" ]] \
|
if [[ "${dest_path:0:1}" == "/" ]]; then
|
||||||
&& dest_path="${dest_path#/}"
|
dest_path="${dest_path#/}"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Complete dest_path if ended by a /
|
# Complete dest_path if ended by a /
|
||||||
[[ "${dest_path: -1}" == "/" ]] \
|
if [[ "${dest_path: -1}" == "/" ]]; then
|
||||||
&& dest_path="${dest_path}/$(basename $src_path)"
|
dest_path="${dest_path}/$(basename $src_path)"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if dest_path already exists in tmp archive
|
# Check if dest_path already exists in tmp archive
|
||||||
[[ ! -e "${dest_path}" ]] || {
|
if [[ -e "${dest_path}" ]]
|
||||||
|
then
|
||||||
ynh_print_err --message="Destination path '${dest_path}' already exist"
|
ynh_print_err --message="Destination path '${dest_path}' already exist"
|
||||||
return 1
|
return 1
|
||||||
}
|
fi
|
||||||
|
|
||||||
# Add the relative current working directory to the destination path
|
# Add the relative current working directory to the destination path
|
||||||
local rel_dir="${YNH_CWD#$YNH_BACKUP_DIR}"
|
local rel_dir="${YNH_CWD#$YNH_BACKUP_DIR}"
|
||||||
|
@ -142,15 +149,15 @@ ynh_backup() {
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# Write file to backup into backup_list
|
# Write file to backup into backup_list
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
local src=$(echo "${src_path}" | sed -r 's/"/\"\"/g')
|
local src=$(echo "${src_path}" | sed --regexp-extended 's/"/\"\"/g')
|
||||||
local dest=$(echo "${dest_path}" | sed -r 's/"/\"\"/g')
|
local dest=$(echo "${dest_path}" | sed --regexp-extended 's/"/\"\"/g')
|
||||||
echo "\"${src}\",\"${dest}\"" >> "${YNH_BACKUP_CSV}"
|
echo "\"${src}\",\"${dest}\"" >> "${YNH_BACKUP_CSV}"
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
|
||||||
# Create the parent dir of the destination path
|
# Create the parent dir of the destination path
|
||||||
# It's for retro compatibility, some script consider ynh_backup creates this dir
|
# It's for retro compatibility, some script consider ynh_backup creates this dir
|
||||||
mkdir -p $(dirname "$YNH_BACKUP_DIR/${dest_path}")
|
mkdir --parents $(dirname "$YNH_BACKUP_DIR/${dest_path}")
|
||||||
}
|
}
|
||||||
|
|
||||||
# Restore all files that were previously backuped in a core backup script or app backup script
|
# Restore all files that were previously backuped in a core backup script or app backup script
|
||||||
|
@ -164,10 +171,11 @@ ynh_restore () {
|
||||||
REL_DIR="${REL_DIR%/}/"
|
REL_DIR="${REL_DIR%/}/"
|
||||||
|
|
||||||
# For each destination path begining by $REL_DIR
|
# For each destination path begining by $REL_DIR
|
||||||
cat ${YNH_BACKUP_CSV} | tr -d $'\r' | grep -ohP "^\".*\",\"$REL_DIR.*\"$" | \
|
cat ${YNH_BACKUP_CSV} | tr --delete $'\r' | grep --only-matching --no-filename --perl-regexp "^\".*\",\"$REL_DIR.*\"$" | \
|
||||||
while read line; do
|
while read line
|
||||||
local ORIGIN_PATH=$(echo "$line" | grep -ohP "^\"\K.*(?=\",\".*\"$)")
|
do
|
||||||
local ARCHIVE_PATH=$(echo "$line" | grep -ohP "^\".*\",\"$REL_DIR\K.*(?=\"$)")
|
local ORIGIN_PATH=$(echo "$line" | grep --only-matching --no-filename --perl-regexp "^\"\K.*(?=\",\".*\"$)")
|
||||||
|
local ARCHIVE_PATH=$(echo "$line" | grep --only-matching --no-filename --perl-regexp "^\".*\",\"$REL_DIR\K.*(?=\"$)")
|
||||||
ynh_restore_file --origin_path="$ARCHIVE_PATH" --dest_path="$ORIGIN_PATH"
|
ynh_restore_file --origin_path="$ARCHIVE_PATH" --dest_path="$ORIGIN_PATH"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
@ -199,8 +207,8 @@ with open(sys.argv[1], 'r') as backup_file:
|
||||||
# the right 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 to be backuped or relative path to $YNH_CWD where it is located in the backup archive
|
# | arg: -o, --origin_path= - Path where was located the file or the directory before to be backuped or relative path to $YNH_CWD where it is located in the backup archive
|
||||||
# | arg: -d, --dest_path - Path where restore the file or the dir, if unspecified, the destination will be ORIGIN_PATH or if the ORIGIN_PATH doesn't exist in the archive, the destination will be searched into backup.csv
|
# | arg: -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:
|
# examples:
|
||||||
|
@ -217,24 +225,25 @@ with open(sys.argv[1], 'r') as backup_file:
|
||||||
# /etc/nginx/conf.d/$domain.d/$app.conf
|
# /etc/nginx/conf.d/$domain.d/$app.conf
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
|
# Requires YunoHost version 3.5.0 or higher for the argument --not_mandatory
|
||||||
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
|
||||||
declare -Ar args_array=( [o]=origin_path= [d]=dest_path= [m]=not_mandatory )
|
local -A args_array=( [o]=origin_path= [d]=dest_path= [m]=not_mandatory )
|
||||||
local origin_path
|
local origin_path
|
||||||
local archive_path
|
|
||||||
local dest_path
|
local dest_path
|
||||||
local not_mandatory
|
local not_mandatory
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
local origin_path="/${origin_path#/}"
|
origin_path="/${origin_path#/}"
|
||||||
local archive_path="$YNH_CWD${origin_path}"
|
|
||||||
# Default value for dest_path = /$origin_path
|
# Default value for dest_path = /$origin_path
|
||||||
local dest_path="${dest_path:-$origin_path}"
|
dest_path="${dest_path:-$origin_path}"
|
||||||
local not_mandatory="${not_mandatory:-0}"
|
not_mandatory="${not_mandatory:-0}"
|
||||||
|
|
||||||
|
local archive_path="$YNH_CWD${origin_path}"
|
||||||
# If archive_path doesn't exist, search for a corresponding path in CSV
|
# If archive_path doesn't exist, search for a corresponding path in CSV
|
||||||
if [ ! -d "$archive_path" ] && [ ! -f "$archive_path" ] && [ ! -L "$archive_path" ]; then
|
if [ ! -d "$archive_path" ] && [ ! -f "$archive_path" ] && [ ! -L "$archive_path" ]
|
||||||
|
then
|
||||||
if [ "$not_mandatory" == "0" ]
|
if [ "$not_mandatory" == "0" ]
|
||||||
then
|
then
|
||||||
archive_path="$YNH_BACKUP_DIR/$(_get_archive_path \"$origin_path\")"
|
archive_path="$YNH_BACKUP_DIR/$(_get_archive_path \"$origin_path\")"
|
||||||
|
@ -247,10 +256,10 @@ ynh_restore_file () {
|
||||||
if [[ -e "${dest_path}" ]]
|
if [[ -e "${dest_path}" ]]
|
||||||
then
|
then
|
||||||
# Check if the file/dir size is less than 500 Mo
|
# Check if the file/dir size is less than 500 Mo
|
||||||
if [[ $(du -sb ${dest_path} | cut -d"/" -f1) -le "500000000" ]]
|
if [[ $(du --summarize --bytes ${dest_path} | cut --delimiter="/" --fields=1) -le "500000000" ]]
|
||||||
then
|
then
|
||||||
local backup_file="/home/yunohost.conf/backup/${dest_path}.backup.$(date '+%Y%m%d.%H%M%S')"
|
local backup_file="/home/yunohost.conf/backup/${dest_path}.backup.$(date '+%Y%m%d.%H%M%S')"
|
||||||
mkdir -p "$(dirname "$backup_file")"
|
mkdir --parents "$(dirname "$backup_file")"
|
||||||
mv "${dest_path}" "$backup_file" # Move the current file or directory
|
mv "${dest_path}" "$backup_file" # Move the current file or directory
|
||||||
else
|
else
|
||||||
ynh_secure_remove --file=${dest_path}
|
ynh_secure_remove --file=${dest_path}
|
||||||
|
@ -258,15 +267,17 @@ ynh_restore_file () {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Restore origin_path into dest_path
|
# Restore origin_path into dest_path
|
||||||
mkdir -p $(dirname "$dest_path")
|
mkdir --parents $(dirname "$dest_path")
|
||||||
|
|
||||||
# Do a copy if it's just a mounting point
|
# Do a copy if it's just a mounting point
|
||||||
if mountpoint -q $YNH_BACKUP_DIR; then
|
if mountpoint --quiet $YNH_BACKUP_DIR
|
||||||
if [[ -d "${archive_path}" ]]; then
|
then
|
||||||
|
if [[ -d "${archive_path}" ]]
|
||||||
|
then
|
||||||
archive_path="${archive_path}/."
|
archive_path="${archive_path}/."
|
||||||
mkdir -p "$dest_path"
|
mkdir --parents "$dest_path"
|
||||||
fi
|
fi
|
||||||
cp -a "$archive_path" "${dest_path}"
|
cp --archive "$archive_path" "${dest_path}"
|
||||||
# Do a move if YNH_BACKUP_DIR is already a copy
|
# Do a move if YNH_BACKUP_DIR is already a copy
|
||||||
else
|
else
|
||||||
mv "$archive_path" "${dest_path}"
|
mv "$archive_path" "${dest_path}"
|
||||||
|
@ -287,22 +298,22 @@ ynh_bind_or_cp() {
|
||||||
|
|
||||||
# Calculate and store a file checksum into the app settings
|
# Calculate and store a file checksum into the app settings
|
||||||
#
|
#
|
||||||
# $app should be defined when calling this helper
|
|
||||||
#
|
|
||||||
# usage: ynh_store_file_checksum --file=file
|
# usage: ynh_store_file_checksum --file=file
|
||||||
# | arg: -f, --file - The file on which the checksum will performed, then stored.
|
# | arg: -f, --file= - The file on which the checksum will performed, then stored.
|
||||||
|
#
|
||||||
|
# $app should be defined when calling this helper
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# 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
|
||||||
declare -Ar args_array=( [f]=file= )
|
local -A args_array=( [f]=file= )
|
||||||
local file
|
local file
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_'
|
local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_'
|
||||||
ynh_app_setting_set --app=$app --key=$checksum_setting_name --value=$(md5sum "$file" | cut -d' ' -f1)
|
ynh_app_setting_set --app=$app --key=$checksum_setting_name --value=$(md5sum "$file" | cut --delimiter=' ' --fields=1)
|
||||||
|
|
||||||
# If backup_file_checksum isn't empty, ynh_backup_if_checksum_is_different has made a backup
|
# If backup_file_checksum isn't empty, ynh_backup_if_checksum_is_different has made a backup
|
||||||
if [ -n "${backup_file_checksum-}" ]
|
if [ -n "${backup_file_checksum-}" ]
|
||||||
|
@ -321,14 +332,14 @@ ynh_store_file_checksum () {
|
||||||
# modified config files.
|
# modified config files.
|
||||||
#
|
#
|
||||||
# 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: the name of a backup file, or nothing
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# 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
|
||||||
declare -Ar args_array=( [f]=file= )
|
local -A args_array=( [f]=file= )
|
||||||
local file
|
local file
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -339,11 +350,11 @@ ynh_backup_if_checksum_is_different () {
|
||||||
backup_file_checksum=""
|
backup_file_checksum=""
|
||||||
if [ -n "$checksum_value" ]
|
if [ -n "$checksum_value" ]
|
||||||
then # Proceed only if a value was stored into the app settings
|
then # Proceed only if a value was stored into the app settings
|
||||||
if [ -e $file ] && ! echo "$checksum_value $file" | md5sum -c --status
|
if [ -e $file ] && ! echo "$checksum_value $file" | md5sum --check --status
|
||||||
then # If the checksum is now different
|
then # If the checksum is now different
|
||||||
backup_file_checksum="/home/yunohost.conf/backup/$file.backup.$(date '+%Y%m%d.%H%M%S')"
|
backup_file_checksum="/home/yunohost.conf/backup/$file.backup.$(date '+%Y%m%d.%H%M%S')"
|
||||||
mkdir -p "$(dirname "$backup_file_checksum")"
|
mkdir --parents "$(dirname "$backup_file_checksum")"
|
||||||
cp -a "$file" "$backup_file_checksum" # Backup the current file
|
cp --archive "$file" "$backup_file_checksum" # Backup the current file
|
||||||
ynh_print_warn "File $file has been manually modified since the installation or last upgrade. So it has been duplicated in $backup_file_checksum"
|
ynh_print_warn "File $file has been manually modified since the installation or last upgrade. So it has been duplicated in $backup_file_checksum"
|
||||||
echo "$backup_file_checksum" # Return the name of the backup file
|
echo "$backup_file_checksum" # Return the name of the backup file
|
||||||
fi
|
fi
|
||||||
|
@ -352,16 +363,16 @@ ynh_backup_if_checksum_is_different () {
|
||||||
|
|
||||||
# Delete a file checksum from the app settings
|
# Delete a file checksum from the app settings
|
||||||
#
|
#
|
||||||
# $app should be defined when calling this helper
|
# usage: ynh_delete_file_checksum --file=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
|
||||||
#
|
#
|
||||||
|
# $app should be defined when calling this helper
|
||||||
|
#
|
||||||
# Requires YunoHost version 3.3.1 or higher.
|
# 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
|
||||||
declare -Ar args_array=( [f]=file= )
|
local -A args_array=( [f]=file= )
|
||||||
local file
|
local file
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -394,7 +405,7 @@ ynh_backup_before_upgrade () {
|
||||||
if [ "$NO_BACKUP_UPGRADE" -eq 0 ]
|
if [ "$NO_BACKUP_UPGRADE" -eq 0 ]
|
||||||
then
|
then
|
||||||
# Check if a backup already exists with the prefix 1
|
# Check if a backup already exists with the prefix 1
|
||||||
if yunohost backup list | grep -q $app_bck-pre-upgrade1
|
if yunohost backup list | grep --quiet $app_bck-pre-upgrade1
|
||||||
then
|
then
|
||||||
# Prefix becomes 2 to preserve the previous backup
|
# Prefix becomes 2 to preserve the previous backup
|
||||||
backup_number=2
|
backup_number=2
|
||||||
|
@ -406,7 +417,7 @@ ynh_backup_before_upgrade () {
|
||||||
if [ "$?" -eq 0 ]
|
if [ "$?" -eq 0 ]
|
||||||
then
|
then
|
||||||
# If the backup succeeded, remove the previous backup
|
# If the backup succeeded, remove the previous backup
|
||||||
if yunohost backup list | grep -q $app_bck-pre-upgrade$old_backup_number
|
if yunohost backup list | grep --quiet $app_bck-pre-upgrade$old_backup_number
|
||||||
then
|
then
|
||||||
# Remove the previous backup only if it exists
|
# Remove the previous backup only if it exists
|
||||||
yunohost backup delete $app_bck-pre-upgrade$old_backup_number > /dev/null
|
yunohost backup delete $app_bck-pre-upgrade$old_backup_number > /dev/null
|
||||||
|
@ -438,7 +449,7 @@ ynh_restore_upgradebackup () {
|
||||||
if [ "$NO_BACKUP_UPGRADE" -eq 0 ]
|
if [ "$NO_BACKUP_UPGRADE" -eq 0 ]
|
||||||
then
|
then
|
||||||
# Check if an existing backup can be found before removing and restoring the application.
|
# Check if an existing backup can be found before removing and restoring the application.
|
||||||
if yunohost backup list | grep -q $app_bck-pre-upgrade$backup_number
|
if yunohost backup list | grep --quiet $app_bck-pre-upgrade$backup_number
|
||||||
then
|
then
|
||||||
# Remove the application then restore it
|
# Remove the application then restore it
|
||||||
yunohost app remove $app
|
yunohost app remove $app
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
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
|
local legacy_args=lrmptv
|
||||||
declare -Ar args_array=( [l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template [v]=others_var=)
|
local -A args_array=( [l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template [v]=others_var=)
|
||||||
local logpath
|
local logpath
|
||||||
local failregex
|
local failregex
|
||||||
local max_retry
|
local max_retry
|
||||||
|
@ -74,9 +74,10 @@ ynh_add_fail2ban_config () {
|
||||||
local use_template
|
local use_template
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
use_template="${use_template:-0}"
|
|
||||||
max_retry=${max_retry:-3}
|
max_retry=${max_retry:-3}
|
||||||
ports=${ports:-http,https}
|
ports=${ports:-http,https}
|
||||||
|
others_var=${others_var:-}
|
||||||
|
use_template="${use_template:-0}"
|
||||||
|
|
||||||
finalfail2banjailconf="/etc/fail2ban/jail.d/$app.conf"
|
finalfail2banjailconf="/etc/fail2ban/jail.d/$app.conf"
|
||||||
finalfail2banfilterconf="/etc/fail2ban/filter.d/$app.conf"
|
finalfail2banfilterconf="/etc/fail2ban/filter.d/$app.conf"
|
||||||
|
@ -96,7 +97,8 @@ ynh_add_fail2ban_config () {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Replace all other variable given as arguments
|
# Replace all other variable given as arguments
|
||||||
for var_to_replace in ${others_var:-}; do
|
for var_to_replace in $others_var
|
||||||
|
do
|
||||||
# ${var_to_replace^^} make the content of the variable on upper-cases
|
# ${var_to_replace^^} make the content of the variable on upper-cases
|
||||||
# ${!var_to_replace} get the content of the variable named $var_to_replace
|
# ${!var_to_replace} get the content of the variable named $var_to_replace
|
||||||
ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalfail2banjailconf"
|
ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalfail2banjailconf"
|
||||||
|
@ -130,10 +132,11 @@ EOF
|
||||||
ynh_store_file_checksum "$finalfail2banjailconf"
|
ynh_store_file_checksum "$finalfail2banjailconf"
|
||||||
ynh_store_file_checksum "$finalfail2banfilterconf"
|
ynh_store_file_checksum "$finalfail2banfilterconf"
|
||||||
|
|
||||||
ynh_systemd_action --service_name=fail2ban --action=reload
|
ynh_systemd_action --service_name=fail2ban --action=reload --line_match="(Started|Reloaded) Fail2Ban Service" --log_path=systemd
|
||||||
|
|
||||||
local fail2ban_error="$(journalctl -u fail2ban | tail -n50 | grep "WARNING.*$app.*")"
|
local fail2ban_error="$(journalctl --unit=fail2ban | tail --lines=50 | grep "WARNING.*$app.*")"
|
||||||
if [[ -n "$fail2ban_error" ]]; then
|
if [[ -n "$fail2ban_error" ]]
|
||||||
|
then
|
||||||
ynh_print_err --message="Fail2ban failed to load the jail for $app"
|
ynh_print_err --message="Fail2ban failed to load the jail for $app"
|
||||||
ynh_print_warn --message="${fail2ban_error#*WARNING}"
|
ynh_print_warn --message="${fail2ban_error#*WARNING}"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#
|
#
|
||||||
# example: function my_helper()
|
# example: function my_helper()
|
||||||
# {
|
# {
|
||||||
# declare -Ar args_array=( [a]=arg1= [b]=arg2= [c]=arg3 )
|
# local -A args_array=( [a]=arg1= [b]=arg2= [c]=arg3 )
|
||||||
# local arg1
|
# local arg1
|
||||||
# local arg2
|
# local arg2
|
||||||
# local arg3
|
# local arg3
|
||||||
|
@ -22,13 +22,13 @@
|
||||||
# This helper need an array, named "args_array" with all the arguments used by the helper
|
# This helper need an array, named "args_array" with all the arguments used by the helper
|
||||||
# that want to use ynh_handle_getopts_args
|
# that want to use ynh_handle_getopts_args
|
||||||
# Be carreful, this array has to be an associative array, as the following example:
|
# Be carreful, this array has to be an associative array, as the following example:
|
||||||
# declare -Ar args_array=( [a]=arg1 [b]=arg2= [c]=arg3 )
|
# local -A args_array=( [a]=arg1 [b]=arg2= [c]=arg3 )
|
||||||
# Let's explain this array:
|
# Let's explain this array:
|
||||||
# a, b and c are short options, -a, -b and -c
|
# a, b and c are short options, -a, -b and -c
|
||||||
# arg1, arg2 and arg3 are the long options associated to the previous short ones. --arg1, --arg2 and --arg3
|
# arg1, arg2 and arg3 are the long options associated to the previous short ones. --arg1, --arg2 and --arg3
|
||||||
# For each option, a short and long version has to be defined.
|
# For each option, a short and long version has to be defined.
|
||||||
# Let's see something more significant
|
# Let's see something more significant
|
||||||
# declare -Ar args_array=( [u]=user [f]=finalpath= [d]=database )
|
# local -A args_array=( [u]=user [f]=finalpath= [d]=database )
|
||||||
#
|
#
|
||||||
# NB: Because we're using 'declare' without -g, the array will be declared as a local variable.
|
# NB: Because we're using 'declare' without -g, the array will be declared as a local variable.
|
||||||
#
|
#
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
# Requires YunoHost version 3.2.2 or higher.
|
# 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 +o xtrace # set +x
|
||||||
if [ $# -ne 0 ]
|
if [ $# -ne 0 ]
|
||||||
then
|
then
|
||||||
# Store arguments in an array to keep each argument separated
|
# Store arguments in an array to keep each argument separated
|
||||||
|
@ -126,7 +126,8 @@ ynh_handle_getopts_args () {
|
||||||
|
|
||||||
# If the first argument is longer than 2 characters,
|
# If the first argument is longer than 2 characters,
|
||||||
# There's a value attached to the option, in the same array cell
|
# There's a value attached to the option, in the same array cell
|
||||||
if [ ${#all_args[0]} -gt 2 ]; then
|
if [ ${#all_args[0]} -gt 2 ]
|
||||||
|
then
|
||||||
# Remove the option and the space, so keep only the value itself.
|
# Remove the option and the space, so keep only the value itself.
|
||||||
all_args[0]="${all_args[0]#-${parameter} }"
|
all_args[0]="${all_args[0]#-${parameter} }"
|
||||||
# Reduce the value of shift, because the option has been removed manually
|
# Reduce the value of shift, because the option has been removed manually
|
||||||
|
@ -147,6 +148,9 @@ ynh_handle_getopts_args () {
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
|
# Ignore empty parameters
|
||||||
|
if [ -n "${all_args[$i]}" ]
|
||||||
|
then
|
||||||
# Else, add this value to this option
|
# Else, add this value to this option
|
||||||
# Each value will be separated by ';'
|
# Each value will be separated by ';'
|
||||||
if [ -n "${!option_var}" ]
|
if [ -n "${!option_var}" ]
|
||||||
|
@ -166,6 +170,7 @@ ynh_handle_getopts_args () {
|
||||||
# So... Stop fucking arguing each time that eval is evil... Go find an other working solution if you can find one!
|
# 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]}"'
|
eval ${option_var}+='"${all_args[$i]}"'
|
||||||
|
fi
|
||||||
shift_value=$(( shift_value + 1 ))
|
shift_value=$(( shift_value + 1 ))
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
@ -193,7 +198,8 @@ ynh_handle_getopts_args () {
|
||||||
getopts_parameters=${legacy_args:-${getopts_parameters//:}}
|
getopts_parameters=${legacy_args:-${getopts_parameters//:}}
|
||||||
# Get the option_flag from getopts_parameters, by using the option_flag according to the position of the argument.
|
# Get the option_flag from getopts_parameters, by using the option_flag according to the position of the argument.
|
||||||
option_flag=${getopts_parameters:$i:1}
|
option_flag=${getopts_parameters:$i:1}
|
||||||
if [ -z "$option_flag" ]; then
|
if [ -z "$option_flag" ]
|
||||||
|
then
|
||||||
ynh_print_warn --message="Too many arguments ! \"${arguments[$i]}\" will be ignored."
|
ynh_print_warn --message="Too many arguments ! \"${arguments[$i]}\" will be ignored."
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
@ -214,5 +220,5 @@ ynh_handle_getopts_args () {
|
||||||
parse_arg "${arguments[@]}"
|
parse_arg "${arguments[@]}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
set -x
|
set -o xtrace # set -x
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,13 @@
|
||||||
# | arg: -t, --total - Count total RAM+swap
|
# | arg: -t, --total - Count total RAM+swap
|
||||||
# | arg: -s, --ignore_swap - Ignore swap, consider only real RAM
|
# | arg: -s, --ignore_swap - Ignore swap, consider only real RAM
|
||||||
# | arg: -o, --only_swap - Ignore real RAM, consider only swap
|
# | arg: -o, --only_swap - Ignore real RAM, consider only swap
|
||||||
|
# | ret: the amount of free ram
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_get_ram () {
|
ynh_get_ram () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=ftso
|
local legacy_args=ftso
|
||||||
declare -Ar args_array=( [f]=free [t]=total [s]=ignore_swap [o]=only_swap )
|
local -A args_array=( [f]=free [t]=total [s]=ignore_swap [o]=only_swap )
|
||||||
local free
|
local free
|
||||||
local total
|
local total
|
||||||
local ignore_swap
|
local ignore_swap
|
||||||
|
@ -67,15 +70,18 @@ ynh_get_ram () {
|
||||||
# Return 0 or 1 depending if the system has a given amount of RAM+swap free or total
|
# Return 0 or 1 depending if the system has a given amount of RAM+swap free or total
|
||||||
#
|
#
|
||||||
# usage: ynh_require_ram --required=RAM required in Mb [--free|--total] [--ignore_swap|--only_swap]
|
# usage: ynh_require_ram --required=RAM required in Mb [--free|--total] [--ignore_swap|--only_swap]
|
||||||
# | arg: -r, --required - The amount to require, in Mb
|
# | arg: -r, --required= - The amount to require, in Mb
|
||||||
# | arg: -f, --free - Count free RAM+swap
|
# | arg: -f, --free - Count free RAM+swap
|
||||||
# | arg: -t, --total - Count total RAM+swap
|
# | arg: -t, --total - Count total RAM+swap
|
||||||
# | arg: -s, --ignore_swap - Ignore swap, consider only real RAM
|
# | arg: -s, --ignore_swap - Ignore swap, consider only real RAM
|
||||||
# | arg: -o, --only_swap - Ignore real RAM, consider only swap
|
# | arg: -o, --only_swap - Ignore real RAM, consider only swap
|
||||||
|
# | exit: Return 1 if the ram is under the requirement, 0 otherwise.
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_require_ram () {
|
ynh_require_ram () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=rftso
|
local legacy_args=rftso
|
||||||
declare -Ar args_array=( [r]=required= [f]=free [t]=total [s]=ignore_swap [o]=only_swap )
|
local -A args_array=( [r]=required= [f]=free [t]=total [s]=ignore_swap [o]=only_swap )
|
||||||
local required
|
local required
|
||||||
local free
|
local free
|
||||||
local total
|
local total
|
||||||
|
|
|
@ -3,30 +3,34 @@
|
||||||
# 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]
|
||||||
|
# | arg: -m, --message= - Message to display
|
||||||
|
# | arg: -c, --ret_code= - Exit code to exit with
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.4.0 or higher.
|
# 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
|
||||||
declare -Ar args_array=( [m]=message= [c]=ret_code= )
|
local -A args_array=( [m]=message= [c]=ret_code= )
|
||||||
local message
|
local message
|
||||||
local ret_code
|
local ret_code
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
ret_code=${ret_code:-1}
|
||||||
|
|
||||||
echo "$message" 1>&2
|
echo "$message" 1>&2
|
||||||
exit "${ret_code:-1}"
|
exit "$ret_code"
|
||||||
}
|
}
|
||||||
|
|
||||||
# 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"
|
||||||
|
# | arg: -m, --message= - Message to display
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.2.0 or higher.
|
# 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
|
||||||
declare -Ar args_array=( [m]=message= )
|
local -A args_array=( [m]=message= )
|
||||||
local message
|
local message
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -46,11 +50,11 @@ ynh_print_info() {
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# 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
|
||||||
cp -a ${ynh_cli_log} ${ynh_cli_log}-move
|
cp --archive ${ynh_cli_log} ${ynh_cli_log}-move
|
||||||
eval $@
|
eval $@
|
||||||
local exit_code=$?
|
local exit_code=$?
|
||||||
mv ${ynh_cli_log}-move ${ynh_cli_log}
|
mv ${ynh_cli_log}-move ${ynh_cli_log}
|
||||||
return $?
|
return $exit_code
|
||||||
}
|
}
|
||||||
|
|
||||||
# Main printer, just in case in the future we have to change anything about that.
|
# Main printer, just in case in the future we have to change anything about that.
|
||||||
|
@ -65,13 +69,13 @@ ynh_print_log () {
|
||||||
# Print a warning on stderr
|
# Print a warning on stderr
|
||||||
#
|
#
|
||||||
# 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.
|
# 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
|
||||||
declare -Ar args_array=( [m]=message= )
|
local -A args_array=( [m]=message= )
|
||||||
local message
|
local message
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -82,13 +86,13 @@ ynh_print_warn () {
|
||||||
# Print an error on stderr
|
# Print an error on stderr
|
||||||
#
|
#
|
||||||
# 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.
|
# 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
|
||||||
declare -Ar args_array=( [m]=message= )
|
local -A args_array=( [m]=message= )
|
||||||
local message
|
local message
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -100,13 +104,12 @@ ynh_print_err () {
|
||||||
#
|
#
|
||||||
# usage: ynh_exec_err your_command
|
# usage: ynh_exec_err your_command
|
||||||
# usage: ynh_exec_err "your_command | other_command"
|
# usage: ynh_exec_err "your_command | other_command"
|
||||||
|
# | arg: command - command to execute
|
||||||
#
|
#
|
||||||
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
||||||
#
|
#
|
||||||
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
||||||
#
|
#
|
||||||
# | arg: command - command to execute
|
|
||||||
#
|
|
||||||
# Requires YunoHost version 3.2.0 or higher.
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_exec_err () {
|
ynh_exec_err () {
|
||||||
ynh_print_err "$(eval $@)"
|
ynh_print_err "$(eval $@)"
|
||||||
|
@ -116,13 +119,12 @@ ynh_exec_err () {
|
||||||
#
|
#
|
||||||
# usage: ynh_exec_warn your_command
|
# usage: ynh_exec_warn your_command
|
||||||
# usage: ynh_exec_warn "your_command | other_command"
|
# usage: ynh_exec_warn "your_command | other_command"
|
||||||
|
# | arg: command - command to execute
|
||||||
#
|
#
|
||||||
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
||||||
#
|
#
|
||||||
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
||||||
#
|
#
|
||||||
# | arg: command - command to execute
|
|
||||||
#
|
|
||||||
# Requires YunoHost version 3.2.0 or higher.
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_exec_warn () {
|
ynh_exec_warn () {
|
||||||
ynh_print_warn "$(eval $@)"
|
ynh_print_warn "$(eval $@)"
|
||||||
|
@ -132,13 +134,12 @@ ynh_exec_warn () {
|
||||||
#
|
#
|
||||||
# usage: ynh_exec_warn_less your_command
|
# usage: ynh_exec_warn_less your_command
|
||||||
# usage: ynh_exec_warn_less "your_command | other_command"
|
# usage: ynh_exec_warn_less "your_command | other_command"
|
||||||
|
# | arg: command - command to execute
|
||||||
#
|
#
|
||||||
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
||||||
#
|
#
|
||||||
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
||||||
#
|
#
|
||||||
# | arg: command - command to execute
|
|
||||||
#
|
|
||||||
# Requires YunoHost version 3.2.0 or higher.
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_exec_warn_less () {
|
ynh_exec_warn_less () {
|
||||||
eval $@ 2>&1
|
eval $@ 2>&1
|
||||||
|
@ -148,13 +149,12 @@ ynh_exec_warn_less () {
|
||||||
#
|
#
|
||||||
# usage: ynh_exec_quiet your_command
|
# usage: ynh_exec_quiet your_command
|
||||||
# usage: ynh_exec_quiet "your_command | other_command"
|
# usage: ynh_exec_quiet "your_command | other_command"
|
||||||
|
# | arg: command - command to execute
|
||||||
#
|
#
|
||||||
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
||||||
#
|
#
|
||||||
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
||||||
#
|
#
|
||||||
# | arg: command - command to execute
|
|
||||||
#
|
|
||||||
# Requires YunoHost version 3.2.0 or higher.
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_exec_quiet () {
|
ynh_exec_quiet () {
|
||||||
eval $@ > /dev/null
|
eval $@ > /dev/null
|
||||||
|
@ -164,13 +164,12 @@ ynh_exec_quiet () {
|
||||||
#
|
#
|
||||||
# usage: ynh_exec_fully_quiet your_command
|
# usage: ynh_exec_fully_quiet your_command
|
||||||
# usage: ynh_exec_fully_quiet "your_command | other_command"
|
# usage: ynh_exec_fully_quiet "your_command | other_command"
|
||||||
|
# | arg: command - command to execute
|
||||||
#
|
#
|
||||||
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
||||||
#
|
#
|
||||||
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
||||||
#
|
#
|
||||||
# | arg: command - command to execute
|
|
||||||
#
|
|
||||||
# Requires YunoHost version 3.2.0 or higher.
|
# 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
|
||||||
|
@ -216,22 +215,23 @@ base_time=$(date +%s)
|
||||||
# usage: ynh_script_progression --message=message [--weight=weight] [--time]
|
# usage: ynh_script_progression --message=message [--weight=weight] [--time]
|
||||||
# | 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. The execution time is given for the duration since the previous call. So the weight should be applied to this previous call.
|
# | 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.5.0 or higher.
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_script_progression () {
|
ynh_script_progression () {
|
||||||
set +x
|
set +o xtrace # set +x
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=mwtl
|
local legacy_args=mwtl
|
||||||
declare -Ar args_array=( [m]=message= [w]=weight= [t]=time [l]=last )
|
local -A args_array=( [m]=message= [w]=weight= [t]=time [l]=last )
|
||||||
local message
|
local message
|
||||||
local weight
|
local weight
|
||||||
local time
|
local time
|
||||||
local last
|
local last
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
set +x
|
# Re-disable xtrace, ynh_handle_getopts_args set it back
|
||||||
|
set +o xtrace # set +x
|
||||||
weight=${weight:-1}
|
weight=${weight:-1}
|
||||||
time=${time:-0}
|
time=${time:-0}
|
||||||
last=${last:-0}
|
last=${last:-0}
|
||||||
|
@ -295,7 +295,7 @@ ynh_script_progression () {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ynh_print_info "[$progression_bar] > ${message}${print_exec_time}"
|
ynh_print_info "[$progression_bar] > ${message}${print_exec_time}"
|
||||||
set -x
|
set -o xtrace # set -x
|
||||||
}
|
}
|
||||||
|
|
||||||
# Return data to the Yunohost core for later processing
|
# Return data to the Yunohost core for later processing
|
||||||
|
@ -317,16 +317,16 @@ ynh_return () {
|
||||||
# Requires YunoHost version 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 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 +o xtrace # set +x
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=mt
|
local legacy_args=mt
|
||||||
declare -Ar args_array=( [m]=message= [t]=trace= )
|
local -A args_array=( [m]=message= [t]=trace= )
|
||||||
local message
|
local message
|
||||||
local trace
|
local trace
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
# Redisable xtrace, ynh_handle_getopts_args set it back
|
# Re-disable xtrace, ynh_handle_getopts_args set it back
|
||||||
set +x
|
set +o xtrace # set +x
|
||||||
message=${message:-}
|
message=${message:-}
|
||||||
trace=${trace:-}
|
trace=${trace:-}
|
||||||
|
|
||||||
|
@ -338,7 +338,7 @@ ynh_debug () {
|
||||||
if [ "$trace" == "1" ]
|
if [ "$trace" == "1" ]
|
||||||
then
|
then
|
||||||
ynh_debug --message="Enable debugging"
|
ynh_debug --message="Enable debugging"
|
||||||
set +x
|
set +o xtrace # set +x
|
||||||
# Get the current file descriptor of xtrace
|
# Get the current file descriptor of xtrace
|
||||||
old_bash_xtracefd=$BASH_XTRACEFD
|
old_bash_xtracefd=$BASH_XTRACEFD
|
||||||
# Add the current file name and the line number of any command currently running while tracing.
|
# Add the current file name and the line number of any command currently running while tracing.
|
||||||
|
@ -351,27 +351,26 @@ ynh_debug () {
|
||||||
if [ "$trace" == "0" ]
|
if [ "$trace" == "0" ]
|
||||||
then
|
then
|
||||||
ynh_debug --message="Disable debugging"
|
ynh_debug --message="Disable debugging"
|
||||||
set +x
|
set +o xtrace # 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
|
# Restore stdout
|
||||||
exec 1>&1
|
exec 1>&1
|
||||||
fi
|
fi
|
||||||
# Renable set xtrace
|
# Renable set xtrace
|
||||||
set -x
|
set -o xtrace # set -x
|
||||||
}
|
}
|
||||||
|
|
||||||
# Execute a command and print the result as debug
|
# Execute a command and print the result as debug
|
||||||
#
|
#
|
||||||
# usage: ynh_debug_exec your_command
|
# usage: ynh_debug_exec your_command
|
||||||
# usage: ynh_debug_exec "your_command | other_command"
|
# usage: ynh_debug_exec "your_command | other_command"
|
||||||
|
# | arg: command - command to execute
|
||||||
#
|
#
|
||||||
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
||||||
#
|
#
|
||||||
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
||||||
#
|
#
|
||||||
# | arg: command - command to execute
|
|
||||||
#
|
|
||||||
# Requires YunoHost version 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_debug_exec () {
|
ynh_debug_exec () {
|
||||||
ynh_debug --message="$(eval $@)"
|
ynh_debug --message="$(eval $@)"
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
# 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 - (optional) 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 --logfile is provided, /var/log/${app} will be used as default.
|
# If no --logfile is provided, /var/log/${app} will be used as default.
|
||||||
# logfile can be just a directory, or a full path to a logfile :
|
# logfile can be just a directory, or a full path to a logfile :
|
||||||
|
@ -16,33 +16,38 @@
|
||||||
# the same logrotate config file. 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.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
|
# Requires YunoHost version 3.2.0 or higher for the argument --specific_user
|
||||||
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
|
||||||
declare -Ar args_array=( [l]=logfile= [n]=nonappend [u]=specific_user= [y]=non [a]=append )
|
local -A args_array=( [l]=logfile= [n]=nonappend [u]=specific_user= [y]=non [a]=append )
|
||||||
# [y]=non [a]=append are only for legacy purpose, to not fail on the old option '--non-append'
|
# [y]=non [a]=append are only for legacy purpose, to not fail on the old option '--non-append'
|
||||||
local logfile
|
local logfile
|
||||||
local nonappend
|
local nonappend
|
||||||
local specific_user
|
local specific_user
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
local logfile="${logfile:-}"
|
logfile="${logfile:-}"
|
||||||
local nonappend="${nonappend:-0}"
|
nonappend="${nonappend:-0}"
|
||||||
local specific_user="${specific_user:-}"
|
specific_user="${specific_user:-}"
|
||||||
|
|
||||||
# LEGACY CODE - PRE GETOPTS
|
# LEGACY CODE - PRE GETOPTS
|
||||||
if [ $# -gt 0 ] && [ "$1" == "--non-append" ]; then
|
if [ $# -gt 0 ] && [ "$1" == "--non-append" ]
|
||||||
|
then
|
||||||
nonappend=1
|
nonappend=1
|
||||||
# Destroy this argument for the next command.
|
# Destroy this argument for the next command.
|
||||||
shift
|
shift
|
||||||
elif [ $# -gt 1 ] && [ "$2" == "--non-append" ]; then
|
elif [ $# -gt 1 ] && [ "$2" == "--non-append" ]
|
||||||
|
then
|
||||||
nonappend=1
|
nonappend=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $# -gt 0 ] && [ "$(echo ${1:0:1})" != "-" ]; then
|
if [ $# -gt 0 ] && [ "$(echo ${1:0:1})" != "-" ]
|
||||||
|
then
|
||||||
# If the given logfile parameter already exists as a file, or if it ends up with ".log",
|
# If the given logfile parameter already exists as a file, or if it ends up with ".log",
|
||||||
# we just want to manage a single file
|
# we just want to manage a single file
|
||||||
if [ -f "$1" ] || [ "$(echo ${1##*.})" == "log" ]; then
|
if [ -f "$1" ] || [ "$(echo ${1##*.})" == "log" ]
|
||||||
|
then
|
||||||
local logfile=$1
|
local logfile=$1
|
||||||
# Otherwise we assume we want to manage a directory and all its .log file inside
|
# Otherwise we assume we want to manage a directory and all its .log file inside
|
||||||
else
|
else
|
||||||
|
@ -51,7 +56,7 @@ ynh_use_logrotate () {
|
||||||
fi
|
fi
|
||||||
# LEGACY CODE
|
# LEGACY CODE
|
||||||
|
|
||||||
local customtee="tee -a"
|
local customtee="tee --append"
|
||||||
if [ "$nonappend" -eq 1 ]; then
|
if [ "$nonappend" -eq 1 ]; then
|
||||||
customtee="tee"
|
customtee="tee"
|
||||||
fi
|
fi
|
||||||
|
@ -64,7 +69,8 @@ ynh_use_logrotate () {
|
||||||
logfile="/var/log/${app}/*.log" # Without argument, use a defaut directory in /var/log
|
logfile="/var/log/${app}/*.log" # Without argument, use a defaut directory in /var/log
|
||||||
fi
|
fi
|
||||||
local su_directive=""
|
local su_directive=""
|
||||||
if [[ -n $specific_user ]]; then
|
if [[ -n $specific_user ]]
|
||||||
|
then
|
||||||
su_directive=" # Run logorotate as specific user - group
|
su_directive=" # Run logorotate as specific user - group
|
||||||
su ${specific_user%/*} ${specific_user#*/}"
|
su ${specific_user%/*} ${specific_user#*/}"
|
||||||
fi
|
fi
|
||||||
|
@ -90,7 +96,7 @@ $logfile {
|
||||||
$su_directive
|
$su_directive
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
mkdir -p $(dirname "$logfile") # Create the log directory, if not exist
|
mkdir --parents $(dirname "$logfile") # Create the log directory, if not exist
|
||||||
cat ${app}-logrotate | $customtee /etc/logrotate.d/$app > /dev/null # Append this config to the existing config file, or replace the whole config file (depending on $customtee)
|
cat ${app}-logrotate | $customtee /etc/logrotate.d/$app > /dev/null # Append this config to the existing config file, or replace the whole config file (depending on $customtee)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,19 +4,19 @@ MYSQL_ROOT_PWD_FILE=/etc/yunohost/mysql
|
||||||
|
|
||||||
# Open a connection as a user
|
# Open a connection as a user
|
||||||
#
|
#
|
||||||
# example: ynh_mysql_connect_as 'user' 'pass' <<< "UPDATE ...;"
|
# example: ynh_mysql_connect_as --user="user" --password="pass" <<< "UPDATE ...;"
|
||||||
# example: ynh_mysql_connect_as 'user' 'pass' < /path/to/file.sql
|
# example: ynh_mysql_connect_as --user="user" --password="pass" < /path/to/file.sql
|
||||||
#
|
#
|
||||||
# usage: ynh_mysql_connect_as --user=user --password=password [--database=database]
|
# usage: ynh_mysql_connect_as --user=user --password=password [--database=database]
|
||||||
# | 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.
|
# 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
|
||||||
declare -Ar args_array=( [u]=user= [p]=password= [d]=database= )
|
local -A args_array=( [u]=user= [p]=password= [d]=database= )
|
||||||
local user
|
local user
|
||||||
local password
|
local password
|
||||||
local database
|
local database
|
||||||
|
@ -24,20 +24,20 @@ ynh_mysql_connect_as() {
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
database="${database:-}"
|
database="${database:-}"
|
||||||
|
|
||||||
mysql -u "$user" --password="$password" -B "$database"
|
mysql --user="$user" --password="$password" --batch "$database"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Execute a command as root user
|
# Execute a command as root user
|
||||||
#
|
#
|
||||||
# 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.
|
# 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
|
||||||
declare -Ar args_array=( [s]=sql= [d]=database= )
|
local -A args_array=( [s]=sql= [d]=database= )
|
||||||
local sql
|
local sql
|
||||||
local database
|
local database
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -51,14 +51,14 @@ ynh_mysql_execute_as_root() {
|
||||||
# Execute a command from a file as root user
|
# Execute a command from a file as root user
|
||||||
#
|
#
|
||||||
# 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.
|
# 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
|
||||||
declare -Ar args_array=( [f]=file= [d]=database= )
|
local -A args_array=( [f]=file= [d]=database= )
|
||||||
local file
|
local file
|
||||||
local database
|
local database
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -85,9 +85,12 @@ ynh_mysql_create_db() {
|
||||||
local sql="CREATE DATABASE ${db};"
|
local sql="CREATE DATABASE ${db};"
|
||||||
|
|
||||||
# grant all privilegies to user
|
# grant all privilegies to user
|
||||||
if [[ $# -gt 1 ]]; then
|
if [[ $# -gt 1 ]]
|
||||||
|
then
|
||||||
sql+=" GRANT ALL PRIVILEGES ON ${db}.* TO '${2}'@'localhost'"
|
sql+=" GRANT ALL PRIVILEGES ON ${db}.* TO '${2}'@'localhost'"
|
||||||
[[ -n ${3:-} ]] && sql+=" IDENTIFIED BY '${3}'"
|
if [[ -n ${3:-} ]]; then
|
||||||
|
sql+=" IDENTIFIED BY '${3}'"
|
||||||
|
fi
|
||||||
sql+=" WITH GRANT OPTION;"
|
sql+=" WITH GRANT OPTION;"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -111,22 +114,22 @@ ynh_mysql_drop_db() {
|
||||||
|
|
||||||
# Dump a database
|
# Dump a database
|
||||||
#
|
#
|
||||||
# example: ynh_mysql_dump_db 'roundcube' > ./dump.sql
|
# example: ynh_mysql_dump_db --database=roundcube > ./dump.sql
|
||||||
#
|
#
|
||||||
# usage: ynh_mysql_dump_db --database=database
|
# 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.
|
# 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
|
||||||
declare -Ar args_array=( [d]=database= )
|
local -A args_array=( [d]=database= )
|
||||||
local database
|
local database
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
mysqldump -u "root" -p"$(cat $MYSQL_ROOT_PWD_FILE)" --single-transaction --skip-dump-date "$database"
|
mysqldump --user="root" --password="$(cat $MYSQL_ROOT_PWD_FILE)" --single-transaction --skip-dump-date "$database"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create a user
|
# Create a user
|
||||||
|
@ -146,14 +149,15 @@ ynh_mysql_create_user() {
|
||||||
# Check if a mysql user exists
|
# Check if a mysql user exists
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
# | exit: Return 1 if the user doesn't exist, 0 otherwise.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.2.4 or higher.
|
# 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.
|
||||||
local legacy_args=u
|
local legacy_args=u
|
||||||
declare -Ar args_array=( [u]=user= )
|
local -A args_array=( [u]=user= )
|
||||||
local user
|
local user
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -180,19 +184,19 @@ ynh_mysql_drop_user() {
|
||||||
|
|
||||||
# Create a database, an user and its password. Then store the password in the app's config
|
# Create a database, an user and its password. Then store the password in the app's config
|
||||||
#
|
#
|
||||||
|
# usage: ynh_mysql_setup_db --db_user=user --db_name=name [--db_pwd=pwd]
|
||||||
|
# | arg: -u, --db_user= - Owner of the database
|
||||||
|
# | arg: -n, --db_name= - Name of the database
|
||||||
|
# | arg: -p, --db_pwd= - Password of the database. If not provided, a password will be generated
|
||||||
|
#
|
||||||
# After executing this helper, the password of the created database will be available in $db_pwd
|
# After executing this helper, the password of the created database will be available in $db_pwd
|
||||||
# It will also be stored as "mysqlpwd" into the app settings.
|
# It will also be stored as "mysqlpwd" into the app settings.
|
||||||
#
|
#
|
||||||
# usage: ynh_mysql_setup_db --db_user=user --db_name=name [--db_pwd=pwd]
|
|
||||||
# | arg: -u, --db_user - Owner of the database
|
|
||||||
# | arg: -n, --db_name - Name of the database
|
|
||||||
# | arg: -p, --db_pwd - Password of the database. If not provided, a password will be generated
|
|
||||||
#
|
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# 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
|
||||||
declare -Ar args_array=( [u]=db_user= [n]=db_name= [p]=db_pwd= )
|
local -A args_array=( [u]=db_user= [n]=db_name= [p]=db_pwd= )
|
||||||
local db_user
|
local db_user
|
||||||
local db_name
|
local db_name
|
||||||
db_pwd=""
|
db_pwd=""
|
||||||
|
@ -210,21 +214,22 @@ ynh_mysql_setup_db () {
|
||||||
# Remove a database if it exists, and the associated user
|
# Remove a database if it exists, and the associated user
|
||||||
#
|
#
|
||||||
# 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.
|
# 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
|
||||||
declare -Ar args_array=( [u]=db_user= [n]=db_name= )
|
local -A args_array=( [u]=db_user= [n]=db_name= )
|
||||||
local db_user
|
local db_user
|
||||||
local db_name
|
local db_name
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
local mysql_root_password=$(cat $MYSQL_ROOT_PWD_FILE)
|
local mysql_root_password=$(cat $MYSQL_ROOT_PWD_FILE)
|
||||||
if mysqlshow -u root -p$mysql_root_password | grep -q "^| $db_name"; then # Check if the database exists
|
if mysqlshow --user=root --password=$mysql_root_password | grep --quiet "^| $db_name"
|
||||||
|
then # Check if the database exists
|
||||||
ynh_mysql_drop_db $db_name # Remove the database
|
ynh_mysql_drop_db $db_name # Remove the database
|
||||||
else
|
else
|
||||||
ynh_print_warn --message="Database $db_name not found"
|
ynh_print_warn --message="Database $db_name not found"
|
||||||
|
@ -235,4 +240,3 @@ ynh_mysql_remove_db () {
|
||||||
ynh_mysql_drop_user $db_user
|
ynh_mysql_drop_user $db_user
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,19 +5,20 @@
|
||||||
# example: port=$(ynh_find_port --port=8080)
|
# example: port=$(ynh_find_port --port=8080)
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
# | ret: the port number
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# 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
|
||||||
declare -Ar args_array=( [p]=port= )
|
local -A args_array=( [p]=port= )
|
||||||
local port
|
local port
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
test -n "$port" || ynh_die --message="The argument of ynh_find_port must be a valid port."
|
test -n "$port" || ynh_die --message="The argument of ynh_find_port must be a valid port."
|
||||||
while ss -nltu | awk '{print$5}' | grep -q -E ":$port$" # Check if the port is free
|
while ! ynh_port_available --port=$port
|
||||||
do
|
do
|
||||||
port=$((port+1)) # Else, pass to next port
|
port=$((port+1)) # Else, pass to next port
|
||||||
done
|
done
|
||||||
|
@ -29,18 +30,19 @@ ynh_find_port () {
|
||||||
# example: ynh_port_available --port=1234 || ynh_die "Port 1234 is needs to be available for this app"
|
# example: ynh_port_available --port=1234 || ynh_die "Port 1234 is needs to be available for this app"
|
||||||
#
|
#
|
||||||
# usage: ynh_find_port --port=XYZ
|
# usage: ynh_find_port --port=XYZ
|
||||||
# | arg: -p, --port - port to check
|
# | arg: -p, --port= - port to check
|
||||||
|
# | exit: Return 1 if the port is already used by another process.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.7.x or higher.
|
# Requires YunoHost version 3.8.0 or higher.
|
||||||
ynh_port_available () {
|
ynh_port_available () {
|
||||||
# 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
|
||||||
declare -Ar args_array=( [p]=port= )
|
local -A args_array=( [p]=port= )
|
||||||
local port
|
local port
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
if ss -nltu | grep -q -w :$port
|
if ss --numeric --listening --tcp --udp | awk '{print$5}' | grep --quiet --extended-regexp ":$port$" # Check if the port is free
|
||||||
then
|
then
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
|
@ -51,6 +53,8 @@ ynh_port_available () {
|
||||||
|
|
||||||
# Validate an IP address
|
# Validate an IP address
|
||||||
#
|
#
|
||||||
|
# [internal]
|
||||||
|
#
|
||||||
# usage: ynh_validate_ip --family=family --ip_address=ip_address
|
# usage: ynh_validate_ip --family=family --ip_address=ip_address
|
||||||
# | ret: 0 for valid ip addresses, 1 otherwise
|
# | ret: 0 for valid ip addresses, 1 otherwise
|
||||||
#
|
#
|
||||||
|
@ -63,7 +67,7 @@ ynh_validate_ip()
|
||||||
|
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=fi
|
local legacy_args=fi
|
||||||
declare -Ar args_array=( [f]=family= [i]=ip_address= )
|
local -A args_array=( [f]=family= [i]=ip_address= )
|
||||||
local family
|
local family
|
||||||
local ip_address
|
local ip_address
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -88,6 +92,7 @@ EOF
|
||||||
# example: ynh_validate_ip4 111.222.333.444
|
# example: ynh_validate_ip4 111.222.333.444
|
||||||
#
|
#
|
||||||
# usage: ynh_validate_ip4 --ip_address=ip_address
|
# usage: ynh_validate_ip4 --ip_address=ip_address
|
||||||
|
# | arg: -i, --ip_address= - the ipv4 address to check
|
||||||
# | ret: 0 for valid ipv4 addresses, 1 otherwise
|
# | ret: 0 for valid ipv4 addresses, 1 otherwise
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.2.4 or higher.
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
|
@ -95,12 +100,12 @@ ynh_validate_ip4()
|
||||||
{
|
{
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=i
|
local legacy_args=i
|
||||||
declare -Ar args_array=( [i]=ip_address= )
|
local -A args_array=( [i]=ip_address= )
|
||||||
local ip_address
|
local ip_address
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
ynh_validate_ip 4 $ip_address
|
ynh_validate_ip --family=4 --ip_address=$ip_address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -109,6 +114,7 @@ ynh_validate_ip4()
|
||||||
# example: ynh_validate_ip6 2000:dead:beef::1
|
# example: ynh_validate_ip6 2000:dead:beef::1
|
||||||
#
|
#
|
||||||
# usage: ynh_validate_ip6 --ip_address=ip_address
|
# usage: ynh_validate_ip6 --ip_address=ip_address
|
||||||
|
# | arg: -i, --ip_address= - the ipv6 address to check
|
||||||
# | ret: 0 for valid ipv6 addresses, 1 otherwise
|
# | ret: 0 for valid ipv6 addresses, 1 otherwise
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.2.4 or higher.
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
|
@ -116,10 +122,10 @@ ynh_validate_ip6()
|
||||||
{
|
{
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=i
|
local legacy_args=i
|
||||||
declare -Ar args_array=( [i]=ip_address= )
|
local -A args_array=( [i]=ip_address= )
|
||||||
local ip_address
|
local ip_address
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
ynh_validate_ip 6 $ip_address
|
ynh_validate_ip --family=6 --ip_address=$ip_address
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
# __PORT_2__ by $port_2
|
# __PORT_2__ by $port_2
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.7.2 or higher.
|
# Requires YunoHost version 2.7.2 or higher.
|
||||||
|
# Requires YunoHost version 2.7.13 or higher for dynamic variables
|
||||||
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:-}
|
||||||
|
@ -27,7 +28,8 @@ ynh_add_nginx_config () {
|
||||||
|
|
||||||
# To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable.
|
# To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable.
|
||||||
# Substitute in a nginx config file only if the variable is not empty
|
# Substitute in a nginx config file only if the variable is not empty
|
||||||
if test -n "${path_url:-}"; then
|
if test -n "${path_url:-}"
|
||||||
|
then
|
||||||
# path_url_slash_less is path_url, or a blank value if path_url is only '/'
|
# path_url_slash_less is path_url, or a blank value if path_url is only '/'
|
||||||
local path_url_slash_less=${path_url%/}
|
local path_url_slash_less=${path_url%/}
|
||||||
ynh_replace_string --match_string="__PATH__/" --replace_string="$path_url_slash_less/" --target_file="$finalnginxconf"
|
ynh_replace_string --match_string="__PATH__/" --replace_string="$path_url_slash_less/" --target_file="$finalnginxconf"
|
||||||
|
|
|
@ -15,7 +15,7 @@ export N_PREFIX="$n_install_dir"
|
||||||
ynh_install_n () {
|
ynh_install_n () {
|
||||||
ynh_print_info --message="Installation of N - Node.js version management"
|
ynh_print_info --message="Installation of N - Node.js version management"
|
||||||
# Build an app.src for n
|
# Build an app.src for n
|
||||||
mkdir -p "../conf"
|
mkdir --parents "../conf"
|
||||||
echo "SOURCE_URL=https://github.com/tj/n/archive/v4.1.0.tar.gz
|
echo "SOURCE_URL=https://github.com/tj/n/archive/v4.1.0.tar.gz
|
||||||
SOURCE_SUM=3983fa3f00d4bf85ba8e21f1a590f6e28938093abe0bb950aeea52b1717471fc" > "../conf/n.src"
|
SOURCE_SUM=3983fa3f00d4bf85ba8e21f1a590f6e28938093abe0bb950aeea52b1717471fc" > "../conf/n.src"
|
||||||
# Download and extract n
|
# Download and extract n
|
||||||
|
@ -81,7 +81,9 @@ ynh_use_nodejs () {
|
||||||
alias ynh_npm="$ynh_npm"
|
alias ynh_npm="$ynh_npm"
|
||||||
|
|
||||||
# Load the path of this version of node in $PATH
|
# Load the path of this version of node in $PATH
|
||||||
[[ :$PATH: == *":$nodejs_path"* ]] || PATH="$nodejs_path:$PATH"
|
if [[ :$PATH: != *":$nodejs_path"* ]]; then
|
||||||
|
PATH="$nodejs_path:$PATH"
|
||||||
|
fi
|
||||||
node_PATH="$PATH"
|
node_PATH="$PATH"
|
||||||
# Create an alias to easily load the PATH
|
# Create an alias to easily load the PATH
|
||||||
ynh_node_load_PATH="PATH=$node_PATH"
|
ynh_node_load_PATH="PATH=$node_PATH"
|
||||||
|
@ -89,13 +91,13 @@ ynh_use_nodejs () {
|
||||||
|
|
||||||
# Install a specific version of nodejs
|
# Install a specific version of nodejs
|
||||||
#
|
#
|
||||||
# n (Node version management) uses the PATH variable to store the path of the version of node it is going to use.
|
|
||||||
# That's how it changes the version
|
|
||||||
#
|
|
||||||
# ynh_install_nodejs will install the version of node provided as argument by using n.
|
# ynh_install_nodejs will install the version of node provided as argument by using n.
|
||||||
#
|
#
|
||||||
# usage: ynh_install_nodejs --nodejs_version=nodejs_version
|
# usage: ynh_install_nodejs --nodejs_version=nodejs_version
|
||||||
# | arg: -n, --nodejs_version - Version of node to install. When possible, your should prefer to use major version number (e.g. 8 instead of 8.10.0). The crontab will then handle the update of minor versions when needed.
|
# | arg: -n, --nodejs_version= - Version of node to install. When possible, your should prefer to use major version number (e.g. 8 instead of 8.10.0). The crontab will then handle the update of minor versions when needed.
|
||||||
|
#
|
||||||
|
# n (Node version management) uses the PATH variable to store the path of the version of node it is going to use.
|
||||||
|
# That's how it changes the version
|
||||||
#
|
#
|
||||||
# Refer to ynh_use_nodejs for more information about available commands and variables
|
# Refer to ynh_use_nodejs for more information about available commands and variables
|
||||||
#
|
#
|
||||||
|
@ -105,13 +107,13 @@ ynh_install_nodejs () {
|
||||||
|
|
||||||
# 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
|
||||||
declare -Ar args_array=( [n]=nodejs_version= )
|
local -A args_array=( [n]=nodejs_version= )
|
||||||
local nodejs_version
|
local nodejs_version
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
# Create $n_install_dir
|
# Create $n_install_dir
|
||||||
mkdir -p "$n_install_dir"
|
mkdir --parents "$n_install_dir"
|
||||||
|
|
||||||
# Load n path in PATH
|
# Load n path in PATH
|
||||||
CLEAR_PATH="$n_install_dir/bin:$PATH"
|
CLEAR_PATH="$n_install_dir/bin:$PATH"
|
||||||
|
@ -139,7 +141,7 @@ ynh_install_nodejs () {
|
||||||
test -x /usr/bin/npm_n && mv /usr/bin/npm_n /usr/bin/npm
|
test -x /usr/bin/npm_n && mv /usr/bin/npm_n /usr/bin/npm
|
||||||
|
|
||||||
# Install the requested version of nodejs
|
# Install the requested version of nodejs
|
||||||
uname=$(uname -m)
|
uname=$(uname --machine)
|
||||||
if [[ $uname =~ aarch64 || $uname =~ arm64 ]]
|
if [[ $uname =~ aarch64 || $uname =~ arm64 ]]
|
||||||
then
|
then
|
||||||
n $nodejs_version --arch=arm64
|
n $nodejs_version --arch=arm64
|
||||||
|
@ -196,7 +198,7 @@ ynh_remove_nodejs () {
|
||||||
ynh_secure_remove --file="$n_install_dir"
|
ynh_secure_remove --file="$n_install_dir"
|
||||||
ynh_secure_remove --file="/usr/local/n"
|
ynh_secure_remove --file="/usr/local/n"
|
||||||
sed --in-place "/N_PREFIX/d" /root/.bashrc
|
sed --in-place "/N_PREFIX/d" /root/.bashrc
|
||||||
rm -f /etc/cron.daily/node_update
|
rm --force /etc/cron.daily/node_update
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
YNH_DEFAULT_PHP_VERSION=7.0
|
readonly YNH_DEFAULT_PHP_VERSION=7.0
|
||||||
# Declare the actual php version to use.
|
# Declare the actual php version to use.
|
||||||
# A packager willing to use another version of php can override the variable into its _common.sh.
|
# A packager willing to use another version of php can override the variable into its _common.sh.
|
||||||
YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
|
YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
|
||||||
|
@ -8,16 +8,16 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
|
||||||
# Create a dedicated php-fpm config
|
# Create a dedicated php-fpm config
|
||||||
#
|
#
|
||||||
# usage 1: ynh_add_fpm_config [--phpversion=7.X] [--use_template] [--package=packages] [--dedicated_service]
|
# usage 1: ynh_add_fpm_config [--phpversion=7.X] [--use_template] [--package=packages] [--dedicated_service]
|
||||||
# | arg: -v, --phpversion - Version of php to use.
|
# | arg: -v, --phpversion= - Version of php to use.
|
||||||
# | arg: -t, --use_template - Use this helper in template mode.
|
# | arg: -t, --use_template - Use this helper in template mode.
|
||||||
# | arg: -p, --package - Additionnal php packages to install
|
# | arg: -p, --package= - Additionnal php packages to install
|
||||||
# | arg: -d, --dedicated_service - Use a dedicated php-fpm service instead of the common one.
|
# | arg: -d, --dedicated_service - Use a dedicated php-fpm service instead of the common one.
|
||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# usage 2: ynh_add_fpm_config [--phpversion=7.X] --usage=usage --footprint=footprint [--package=packages] [--dedicated_service]
|
# usage 2: ynh_add_fpm_config [--phpversion=7.X] --usage=usage --footprint=footprint [--package=packages] [--dedicated_service]
|
||||||
# | arg: -v, --phpversion - Version of php to use.
|
# | arg: -v, --phpversion= - Version of php to use.
|
||||||
# | arg: -f, --footprint - Memory footprint of the service (low/medium/high).
|
# | arg: -f, --footprint= - Memory footprint of the service (low/medium/high).
|
||||||
# low - Less than 20Mb of ram by pool.
|
# low - Less than 20Mb of ram by pool.
|
||||||
# medium - Between 20Mb and 40Mb of ram by pool.
|
# medium - Between 20Mb and 40Mb of ram by pool.
|
||||||
# high - More than 40Mb of ram by pool.
|
# high - More than 40Mb of ram by pool.
|
||||||
|
@ -25,12 +25,12 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
|
||||||
# To have this value, use the following command and stress the service.
|
# To have this value, use the following command and stress the service.
|
||||||
# watch -n0.5 ps -o user,cmd,%cpu,rss -u APP
|
# watch -n0.5 ps -o user,cmd,%cpu,rss -u APP
|
||||||
#
|
#
|
||||||
# | arg: -u, --usage - Expected usage of the service (low/medium/high).
|
# | arg: -u, --usage= - Expected usage of the service (low/medium/high).
|
||||||
# low - Personal usage, behind the sso.
|
# low - Personal usage, behind the sso.
|
||||||
# medium - Low usage, few people or/and publicly accessible.
|
# medium - Low usage, few people or/and publicly accessible.
|
||||||
# high - High usage, frequently visited website.
|
# high - High usage, frequently visited website.
|
||||||
#
|
#
|
||||||
# | arg: -p, --package - Additionnal php packages to install for a specific version of php
|
# | arg: -p, --package= - Additionnal php packages to install for a specific version of php
|
||||||
# | arg: -d, --dedicated_service - Use a dedicated php-fpm service instead of the common one.
|
# | arg: -d, --dedicated_service - Use a dedicated php-fpm service instead of the common one.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -56,10 +56,12 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
|
||||||
# children ready to answer.
|
# children ready to answer.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.7.2 or higher.
|
# Requires YunoHost version 2.7.2 or higher.
|
||||||
|
# Requires YunoHost version 3.5.1 or higher for the argument --phpversion
|
||||||
|
# Requires YunoHost version 3.8.1 or higher for the arguments --use_template, --usage, --footprint, --package and --dedicated_service
|
||||||
ynh_add_fpm_config () {
|
ynh_add_fpm_config () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=vtufpd
|
local legacy_args=vtufpd
|
||||||
declare -Ar args_array=( [v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service )
|
local -A args_array=( [v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service )
|
||||||
local phpversion
|
local phpversion
|
||||||
local use_template
|
local use_template
|
||||||
local usage
|
local usage
|
||||||
|
@ -87,13 +89,14 @@ ynh_add_fpm_config () {
|
||||||
if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ]
|
if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ]
|
||||||
then
|
then
|
||||||
# If the argument --package is used, add the packages to ynh_install_php to install them from sury
|
# If the argument --package is used, add the packages to ynh_install_php to install them from sury
|
||||||
if [ -n "$package" ]; then
|
if [ -n "$package" ]
|
||||||
|
then
|
||||||
local additionnal_packages="--package=$package"
|
local additionnal_packages="--package=$package"
|
||||||
else
|
else
|
||||||
local additionnal_packages=""
|
local additionnal_packages=""
|
||||||
fi
|
fi
|
||||||
# Install this specific version of php.
|
# Install this specific version of php.
|
||||||
ynh_install_php --phpversion=$phpversion "$additionnal_packages"
|
ynh_install_php --phpversion="$phpversion" "$additionnal_packages"
|
||||||
elif [ -n "$package" ]
|
elif [ -n "$package" ]
|
||||||
then
|
then
|
||||||
# Install the additionnal packages from the default repository
|
# Install the additionnal packages from the default repository
|
||||||
|
@ -109,13 +112,14 @@ ynh_add_fpm_config () {
|
||||||
local fpm_config_dir="/etc/php/$phpversion/fpm"
|
local fpm_config_dir="/etc/php/$phpversion/fpm"
|
||||||
fi
|
fi
|
||||||
# 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"
|
||||||
fpm_service="php5-fpm"
|
fpm_service="php5-fpm"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create the directory for fpm pools
|
# Create the directory for fpm pools
|
||||||
mkdir -p "$fpm_config_dir/pool.d"
|
mkdir --parents "$fpm_config_dir/pool.d"
|
||||||
|
|
||||||
ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir"
|
ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir"
|
||||||
ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service"
|
ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service"
|
||||||
|
@ -274,7 +278,8 @@ ynh_remove_fpm_config () {
|
||||||
phpversion="${phpversion:-$YNH_DEFAULT_PHP_VERSION}"
|
phpversion="${phpversion:-$YNH_DEFAULT_PHP_VERSION}"
|
||||||
|
|
||||||
# Assume default php files if not set
|
# Assume default php files if not set
|
||||||
if [ -z "$fpm_config_dir" ]; then
|
if [ -z "$fpm_config_dir" ]
|
||||||
|
then
|
||||||
fpm_config_dir="/etc/php/$YNH_DEFAULT_PHP_VERSION/fpm"
|
fpm_config_dir="/etc/php/$YNH_DEFAULT_PHP_VERSION/fpm"
|
||||||
fpm_service="php$YNH_DEFAULT_PHP_VERSION-fpm"
|
fpm_service="php$YNH_DEFAULT_PHP_VERSION-fpm"
|
||||||
fi
|
fi
|
||||||
|
@ -307,12 +312,14 @@ ynh_remove_fpm_config () {
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
# usage: ynh_install_php --phpversion=phpversion [--package=packages]
|
# usage: ynh_install_php --phpversion=phpversion [--package=packages]
|
||||||
# | arg: -v, --phpversion - Version of php to install.
|
# | arg: -v, --phpversion= - Version of php to install.
|
||||||
# | arg: -p, --package - Additionnal php packages to install
|
# | arg: -p, --package= - Additionnal php packages to install
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_install_php () {
|
ynh_install_php () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=vp
|
local legacy_args=vp
|
||||||
declare -Ar args_array=( [v]=phpversion= [p]=package= )
|
local -A args_array=( [v]=phpversion= [p]=package= )
|
||||||
local phpversion
|
local phpversion
|
||||||
local package
|
local package
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -338,7 +345,7 @@ ynh_install_php () {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Add an extra repository for those packages
|
# Add an extra repository for those packages
|
||||||
ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(lsb_release -sc) main" --key="https://packages.sury.org/php/apt.gpg" --priority=995 --name=extra_php_version
|
ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(ynh_get_debian_release) main" --key="https://packages.sury.org/php/apt.gpg" --priority=995 --name=extra_php_version
|
||||||
|
|
||||||
# Install requested dependencies from this extra repository.
|
# Install requested dependencies from this extra repository.
|
||||||
# Install php-fpm first, otherwise php will install apache as a dependency.
|
# Install php-fpm first, otherwise php will install apache as a dependency.
|
||||||
|
@ -361,6 +368,8 @@ ynh_install_php () {
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
# usage: ynh_install_php
|
# usage: ynh_install_php
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_remove_php () {
|
ynh_remove_php () {
|
||||||
# Get the version of php used by this app
|
# Get the version of php used by this app
|
||||||
local phpversion=$(ynh_app_setting_get $app phpversion)
|
local phpversion=$(ynh_app_setting_get $app phpversion)
|
||||||
|
@ -398,7 +407,7 @@ ynh_remove_php () {
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
# usage: ynh_get_scalable_phpfpm --usage=usage --footprint=footprint [--print]
|
# usage: ynh_get_scalable_phpfpm --usage=usage --footprint=footprint [--print]
|
||||||
# | arg: -f, --footprint - Memory footprint of the service (low/medium/high).
|
# | arg: -f, --footprint= - Memory footprint of the service (low/medium/high).
|
||||||
# low - Less than 20Mb of ram by pool.
|
# low - Less than 20Mb of ram by pool.
|
||||||
# medium - Between 20Mb and 40Mb of ram by pool.
|
# medium - Between 20Mb and 40Mb of ram by pool.
|
||||||
# high - More than 40Mb of ram by pool.
|
# high - More than 40Mb of ram by pool.
|
||||||
|
@ -406,7 +415,7 @@ ynh_remove_php () {
|
||||||
# To have this value, use the following command and stress the service.
|
# To have this value, use the following command and stress the service.
|
||||||
# watch -n0.5 ps -o user,cmd,%cpu,rss -u APP
|
# watch -n0.5 ps -o user,cmd,%cpu,rss -u APP
|
||||||
#
|
#
|
||||||
# | arg: -u, --usage - Expected usage of the service (low/medium/high).
|
# | arg: -u, --usage= - Expected usage of the service (low/medium/high).
|
||||||
# low - Personal usage, behind the sso.
|
# low - Personal usage, behind the sso.
|
||||||
# medium - Low usage, few people or/and publicly accessible.
|
# medium - Low usage, few people or/and publicly accessible.
|
||||||
# high - High usage, frequently visited website.
|
# high - High usage, frequently visited website.
|
||||||
|
@ -415,7 +424,7 @@ ynh_remove_php () {
|
||||||
ynh_get_scalable_phpfpm () {
|
ynh_get_scalable_phpfpm () {
|
||||||
local legacy_args=ufp
|
local legacy_args=ufp
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
declare -Ar args_array=( [u]=usage= [f]=footprint= [p]=print )
|
local -A args_array=( [u]=usage= [f]=footprint= [p]=print )
|
||||||
local usage
|
local usage
|
||||||
local footprint
|
local footprint
|
||||||
local print
|
local print
|
||||||
|
@ -524,18 +533,22 @@ ynh_get_scalable_phpfpm () {
|
||||||
ynh_debug --message="Footprint=${footprint}Mb by pool."
|
ynh_debug --message="Footprint=${footprint}Mb by pool."
|
||||||
ynh_debug --message="Process manager=$php_pm"
|
ynh_debug --message="Process manager=$php_pm"
|
||||||
ynh_debug --message="Max RAM=${max_ram}Mb"
|
ynh_debug --message="Max RAM=${max_ram}Mb"
|
||||||
if [ "$php_pm" != "static" ]; then
|
if [ "$php_pm" != "static" ]
|
||||||
|
then
|
||||||
ynh_debug --message="\nMax estimated footprint=$(( $php_max_children * $footprint ))"
|
ynh_debug --message="\nMax estimated footprint=$(( $php_max_children * $footprint ))"
|
||||||
ynh_debug --message="Min estimated footprint=$(( $php_min_spare_servers * $footprint ))"
|
ynh_debug --message="Min estimated footprint=$(( $php_min_spare_servers * $footprint ))"
|
||||||
fi
|
fi
|
||||||
if [ "$php_pm" = "dynamic" ]; then
|
if [ "$php_pm" = "dynamic" ]
|
||||||
|
then
|
||||||
ynh_debug --message="Estimated average footprint=$(( $php_max_spare_servers * $footprint ))"
|
ynh_debug --message="Estimated average footprint=$(( $php_max_spare_servers * $footprint ))"
|
||||||
elif [ "$php_pm" = "static" ]; then
|
elif [ "$php_pm" = "static" ]
|
||||||
|
then
|
||||||
ynh_debug --message="Estimated footprint=$(( $php_max_children * $footprint ))"
|
ynh_debug --message="Estimated footprint=$(( $php_max_children * $footprint ))"
|
||||||
fi
|
fi
|
||||||
ynh_debug --message="\nRaw php-fpm values:"
|
ynh_debug --message="\nRaw php-fpm values:"
|
||||||
ynh_debug --message="pm.max_children = $php_max_children"
|
ynh_debug --message="pm.max_children = $php_max_children"
|
||||||
if [ "$php_pm" = "dynamic" ]; then
|
if [ "$php_pm" = "dynamic" ]
|
||||||
|
then
|
||||||
ynh_debug --message="pm.start_servers = $php_start_servers"
|
ynh_debug --message="pm.start_servers = $php_start_servers"
|
||||||
ynh_debug --message="pm.min_spare_servers = $php_min_spare_servers"
|
ynh_debug --message="pm.min_spare_servers = $php_min_spare_servers"
|
||||||
ynh_debug --message="pm.max_spare_servers = $php_max_spare_servers"
|
ynh_debug --message="pm.max_spare_servers = $php_max_spare_servers"
|
||||||
|
|
|
@ -9,15 +9,15 @@ PSQL_ROOT_PWD_FILE=/etc/yunohost/psql
|
||||||
# ynh_psql_connect_as 'user' 'pass' < /path/to/file.sql
|
# ynh_psql_connect_as 'user' 'pass' < /path/to/file.sql
|
||||||
#
|
#
|
||||||
# usage: ynh_psql_connect_as --user=user --password=password [--database=database]
|
# usage: ynh_psql_connect_as --user=user --password=password [--database=database]
|
||||||
# | 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 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_psql_connect_as() {
|
ynh_psql_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
|
||||||
declare -Ar args_array=([u]=user= [p]=password= [d]=database=)
|
local -A args_array=([u]=user= [p]=password= [d]=database=)
|
||||||
local user
|
local user
|
||||||
local password
|
local password
|
||||||
local database
|
local database
|
||||||
|
@ -31,14 +31,14 @@ ynh_psql_connect_as() {
|
||||||
# Execute a command as root user
|
# Execute a command as root user
|
||||||
#
|
#
|
||||||
# usage: ynh_psql_execute_as_root --sql=sql [--database=database]
|
# usage: ynh_psql_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 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_psql_execute_as_root() {
|
ynh_psql_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
|
||||||
declare -Ar args_array=([s]=sql= [d]=database=)
|
local -A args_array=([s]=sql= [d]=database=)
|
||||||
local sql
|
local sql
|
||||||
local database
|
local database
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -52,14 +52,14 @@ ynh_psql_execute_as_root() {
|
||||||
# Execute a command from a file as root user
|
# Execute a command from a file as root user
|
||||||
#
|
#
|
||||||
# usage: ynh_psql_execute_file_as_root --file=file [--database=database]
|
# usage: ynh_psql_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 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_psql_execute_file_as_root() {
|
ynh_psql_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
|
||||||
declare -Ar args_array=([f]=file= [d]=database=)
|
local -A args_array=([f]=file= [d]=database=)
|
||||||
local file
|
local file
|
||||||
local database
|
local database
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -87,6 +87,7 @@ ynh_psql_create_db() {
|
||||||
|
|
||||||
# grant all privilegies to user
|
# grant all privilegies to user
|
||||||
if [ -n "$user" ]; then
|
if [ -n "$user" ]; then
|
||||||
|
sql+="ALTER DATABASE ${db} OWNER TO ${user};"
|
||||||
sql+="GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${user} WITH GRANT OPTION;"
|
sql+="GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${user} WITH GRANT OPTION;"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -118,14 +119,14 @@ ynh_psql_drop_db() {
|
||||||
# example: ynh_psql_dump_db 'roundcube' > ./dump.sql
|
# example: ynh_psql_dump_db 'roundcube' > ./dump.sql
|
||||||
#
|
#
|
||||||
# usage: ynh_psql_dump_db --database=database
|
# usage: ynh_psql_dump_db --database=database
|
||||||
# | arg: -d, --database - the database name to dump
|
# | arg: -d, --database= - the database name to dump
|
||||||
# | ret: the psqldump output
|
# | ret: the psqldump output
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_psql_dump_db() {
|
ynh_psql_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
|
||||||
declare -Ar args_array=([d]=database=)
|
local -A args_array=([d]=database=)
|
||||||
local database
|
local database
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -151,16 +152,20 @@ ynh_psql_create_user() {
|
||||||
# Check if a psql user exists
|
# Check if a psql user exists
|
||||||
#
|
#
|
||||||
# usage: ynh_psql_user_exists --user=user
|
# usage: ynh_psql_user_exists --user=user
|
||||||
# | arg: -u, --user - the user for which to check existence
|
# | arg: -u, --user= - the user for which to check existence
|
||||||
|
# | exit: Return 1 if the user doesn't exist, 0 otherwise
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_psql_user_exists() {
|
ynh_psql_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
|
||||||
declare -Ar args_array=([u]=user=)
|
local -A args_array=([u]=user=)
|
||||||
local user
|
local user
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';" | grep --quiet "$user" ; then
|
if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';" | grep --quiet "$user"
|
||||||
|
then
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
|
@ -170,16 +175,20 @@ ynh_psql_user_exists() {
|
||||||
# Check if a psql database exists
|
# Check if a psql database exists
|
||||||
#
|
#
|
||||||
# usage: ynh_psql_database_exists --database=database
|
# usage: ynh_psql_database_exists --database=database
|
||||||
# | arg: -d, --database - the database for which to check existence
|
# | arg: -d, --database= - the database for which to check existence
|
||||||
|
# | exit: Return 1 if the database doesn't exist, 0 otherwise
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_psql_database_exists() {
|
ynh_psql_database_exists() {
|
||||||
# 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
|
||||||
declare -Ar args_array=([d]=database=)
|
local -A args_array=([d]=database=)
|
||||||
local database
|
local database
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';" | grep --quiet "$database"; then
|
if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';" | grep --quiet "$database"
|
||||||
|
then
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
|
@ -200,17 +209,19 @@ ynh_psql_drop_user() {
|
||||||
|
|
||||||
# Create a database, an user and its password. Then store the password in the app's config
|
# Create a database, an user and its password. Then store the password in the app's config
|
||||||
#
|
#
|
||||||
|
# usage: ynh_psql_setup_db --db_user=user --db_name=name [--db_pwd=pwd]
|
||||||
|
# | arg: -u, --db_user= - Owner of the database
|
||||||
|
# | arg: -n, --db_name= - Name of the database
|
||||||
|
# | arg: -p, --db_pwd= - Password of the database. If not given, a password will be generated
|
||||||
|
#
|
||||||
# After executing this helper, the password of the created database will be available in $db_pwd
|
# 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.
|
# 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]
|
# Requires YunoHost version 2.7.13 or higher.
|
||||||
# | 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() {
|
ynh_psql_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
|
||||||
declare -Ar args_array=([u]=db_user= [n]=db_name= [p]=db_pwd=)
|
local -A args_array=([u]=db_user= [n]=db_name= [p]=db_pwd=)
|
||||||
local db_user
|
local db_user
|
||||||
local db_name
|
local db_name
|
||||||
db_pwd=""
|
db_pwd=""
|
||||||
|
@ -232,25 +243,29 @@ ynh_psql_setup_db() {
|
||||||
# Remove a database if it exists, and the associated user
|
# Remove a database if it exists, and the associated user
|
||||||
#
|
#
|
||||||
# usage: ynh_psql_remove_db --db_user=user --db_name=name
|
# usage: ynh_psql_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.7.13 or higher.
|
||||||
ynh_psql_remove_db() {
|
ynh_psql_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
|
||||||
declare -Ar args_array=([u]=db_user= [n]=db_name=)
|
local -A args_array=([u]=db_user= [n]=db_name=)
|
||||||
local db_user
|
local db_user
|
||||||
local db_name
|
local db_name
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
if ynh_psql_database_exists --database=$db_name; then # Check if the database exists
|
if ynh_psql_database_exists --database=$db_name
|
||||||
|
then # Check if the database exists
|
||||||
ynh_psql_drop_db $db_name # Remove the database
|
ynh_psql_drop_db $db_name # Remove the database
|
||||||
else
|
else
|
||||||
ynh_print_warn --message="Database $db_name not found"
|
ynh_print_warn --message="Database $db_name not found"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Remove psql user if it exists
|
# Remove psql user if it exists
|
||||||
if ynh_psql_user_exists --user=$db_user; then
|
if ynh_psql_user_exists --user=$db_user
|
||||||
|
then
|
||||||
ynh_psql_drop_user $db_user
|
ynh_psql_drop_user $db_user
|
||||||
else
|
else
|
||||||
ynh_print_warn --message="User $db_user not found"
|
ynh_print_warn --message="User $db_user not found"
|
||||||
|
@ -261,19 +276,24 @@ ynh_psql_remove_db() {
|
||||||
# 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
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.7.13 or higher.
|
||||||
ynh_psql_test_if_first_run() {
|
ynh_psql_test_if_first_run() {
|
||||||
if [ -f "$PSQL_ROOT_PWD_FILE" ]; then
|
if [ -f "$PSQL_ROOT_PWD_FILE" ]
|
||||||
echo "PostgreSQL is already installed, no need to create master password"
|
then
|
||||||
|
ynh_print_info --message="PostgreSQL is already installed, no need to create master password"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local psql_root_password="$(ynh_string_random)"
|
local psql_root_password="$(ynh_string_random)"
|
||||||
echo "$psql_root_password" >$PSQL_ROOT_PWD_FILE
|
echo "$psql_root_password" >$PSQL_ROOT_PWD_FILE
|
||||||
|
|
||||||
if [ -e /etc/postgresql/9.4/ ]; then
|
if [ -e /etc/postgresql/9.4/ ]
|
||||||
|
then
|
||||||
local pg_hba=/etc/postgresql/9.4/main/pg_hba.conf
|
local pg_hba=/etc/postgresql/9.4/main/pg_hba.conf
|
||||||
local logfile=/var/log/postgresql/postgresql-9.4-main.log
|
local logfile=/var/log/postgresql/postgresql-9.4-main.log
|
||||||
elif [ -e /etc/postgresql/9.6/ ]; then
|
elif [ -e /etc/postgresql/9.6/ ]
|
||||||
|
then
|
||||||
local pg_hba=/etc/postgresql/9.6/main/pg_hba.conf
|
local pg_hba=/etc/postgresql/9.6/main/pg_hba.conf
|
||||||
local logfile=/var/log/postgresql/postgresql-9.6-main.log
|
local logfile=/var/log/postgresql/postgresql-9.6-main.log
|
||||||
else
|
else
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
# Get an application setting
|
# Get an application setting
|
||||||
#
|
#
|
||||||
# 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.
|
# 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
|
||||||
declare -Ar args_array=( [a]=app= [k]=key= )
|
local -A args_array=( [a]=app= [k]=key= )
|
||||||
local app
|
local app
|
||||||
local key
|
local key
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -22,15 +22,15 @@ ynh_app_setting_get() {
|
||||||
# Set an application setting
|
# Set an application setting
|
||||||
#
|
#
|
||||||
# usage: ynh_app_setting_set --app=app --key=key --value=value
|
# usage: ynh_app_setting_set --app=app --key=key --value=value
|
||||||
# | 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.
|
# 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
|
||||||
declare -Ar args_array=( [a]=app= [k]=key= [v]=value= )
|
local -A args_array=( [a]=app= [k]=key= [v]=value= )
|
||||||
local app
|
local app
|
||||||
local key
|
local key
|
||||||
local value
|
local value
|
||||||
|
@ -43,14 +43,14 @@ ynh_app_setting_set() {
|
||||||
# Delete an application setting
|
# Delete an application setting
|
||||||
#
|
#
|
||||||
# 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.
|
# 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
|
||||||
declare -Ar args_array=( [a]=app= [k]=key= )
|
local -A args_array=( [a]=app= [k]=key= )
|
||||||
local app
|
local app
|
||||||
local key
|
local key
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -117,14 +117,14 @@ EOF
|
||||||
# example: ynh_webpath_available --domain=some.domain.tld --path_url=/coffee
|
# example: ynh_webpath_available --domain=some.domain.tld --path_url=/coffee
|
||||||
#
|
#
|
||||||
# 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.
|
# 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
|
||||||
declare -Ar args_array=( [d]=domain= [p]=path_url= )
|
local -A args_array=( [d]=domain= [p]=path_url= )
|
||||||
local domain
|
local domain
|
||||||
local path_url
|
local path_url
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -138,15 +138,15 @@ ynh_webpath_available () {
|
||||||
# example: ynh_webpath_register --app=wordpress --domain=some.domain.tld --path_url=/coffee
|
# example: ynh_webpath_register --app=wordpress --domain=some.domain.tld --path_url=/coffee
|
||||||
#
|
#
|
||||||
# usage: ynh_webpath_register --app=app --domain=domain --path_url=path
|
# usage: ynh_webpath_register --app=app --domain=domain --path_url=path
|
||||||
# | 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.
|
# 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
|
||||||
declare -Ar args_array=( [a]=app= [d]=domain= [p]=path_url= )
|
local -A args_array=( [a]=app= [d]=domain= [p]=path_url= )
|
||||||
local app
|
local app
|
||||||
local domain
|
local domain
|
||||||
local path_url
|
local path_url
|
||||||
|
@ -158,12 +158,12 @@ ynh_webpath_register () {
|
||||||
|
|
||||||
# Create a new permission for the app
|
# Create a new permission for the app
|
||||||
#
|
#
|
||||||
# example: ynh_permission_create --permission admin --url /admin --allowed alice bob
|
# example: ynh_permission_create --permission=admin --url=/admin --allowed="alice bob"
|
||||||
#
|
#
|
||||||
# usage: ynh_permission_create --permission "permission" [--url "url"] [--allowed group1 group2]
|
# usage: ynh_permission_create --permission "permission" [--url=url] [--allowed="group1 group2"]
|
||||||
# | arg: permission - the name for the permission (by default a permission named "main" already exist)
|
# | arg: -p, --permission= - the name for the permission (by default a permission named "main" already exist)
|
||||||
# | arg: url - (optional) URL for which access will be allowed/forbidden
|
# | arg: -u, --url= - (optional) URL for which access will be allowed/forbidden
|
||||||
# | arg: allowed - (optional) A list of group/user to allow for the permission
|
# | arg: -a, --allowed= - (optional) A list of group/user to allow for the permission
|
||||||
#
|
#
|
||||||
# If provided, 'url' is assumed to be relative to the app domain/path if they
|
# If provided, 'url' is assumed to be relative to the app domain/path if they
|
||||||
# start with '/'. For example:
|
# start with '/'. For example:
|
||||||
|
@ -180,37 +180,40 @@ ynh_webpath_register () {
|
||||||
ynh_permission_create() {
|
ynh_permission_create() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=pua
|
local legacy_args=pua
|
||||||
declare -Ar args_array=( [p]=permission= [u]=url= [a]=allowed= )
|
local -A args_array=( [p]=permission= [u]=url= [a]=allowed= )
|
||||||
local permission
|
local permission
|
||||||
local url
|
local url
|
||||||
local allowed
|
local allowed
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
url=${url:-}
|
||||||
|
allowed=${allowed:-}
|
||||||
|
|
||||||
if [[ -n ${url:-} ]]; then
|
if [[ -n $url ]]
|
||||||
|
then
|
||||||
url="'$url'"
|
url="'$url'"
|
||||||
else
|
else
|
||||||
url="None"
|
url="None"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n ${allowed:-} ]]; then
|
if [[ -n $allowed ]]; then
|
||||||
allowed=",allowed=['${allowed//';'/"','"}']"
|
allowed=",allowed=['${allowed//';'/"','"}']"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
yunohost tools shell -c "from yunohost.permission import permission_create; permission_create('$app.$permission', url=$url ${allowed:-} , sync_perm=False)"
|
yunohost tools shell -c "from yunohost.permission import permission_create; permission_create('$app.$permission', url=$url $allowed , sync_perm=False)"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Remove a permission for the app (note that when the app is removed all permission is automatically removed)
|
# Remove a permission for the app (note that when the app is removed all permission is automatically removed)
|
||||||
#
|
#
|
||||||
# example: ynh_permission_delete --permission editors
|
# example: ynh_permission_delete --permission=editors
|
||||||
#
|
#
|
||||||
# usage: ynh_permission_delete --permission "permission"
|
# usage: ynh_permission_delete --permission="permission"
|
||||||
# | arg: permission - the name for the permission (by default a permission named "main" is removed automatically when the app is removed)
|
# | arg: -p, --permission= - the name for the permission (by default a permission named "main" is removed automatically when the app is removed)
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.7.0 or higher.
|
# Requires YunoHost version 3.7.0 or higher.
|
||||||
ynh_permission_delete() {
|
ynh_permission_delete() {
|
||||||
# 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
|
||||||
declare -Ar args_array=( [p]=permission= )
|
local -A args_array=( [p]=permission= )
|
||||||
local permission
|
local permission
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
|
@ -220,35 +223,38 @@ ynh_permission_delete() {
|
||||||
# Check if a permission exists
|
# Check if a permission exists
|
||||||
#
|
#
|
||||||
# usage: ynh_permission_exists --permission=permission
|
# usage: ynh_permission_exists --permission=permission
|
||||||
# | arg: -p, --permission - the permission to check
|
# | arg: -p, --permission= - the permission to check
|
||||||
|
# | exit: Return 1 if the permission doesn't exist, 0 otherwise
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.7.0 or higher.
|
# Requires YunoHost version 3.7.0 or higher.
|
||||||
ynh_permission_exists() {
|
ynh_permission_exists() {
|
||||||
# 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
|
||||||
declare -Ar args_array=( [p]=permission= )
|
local -A args_array=( [p]=permission= )
|
||||||
local permission
|
local permission
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
yunohost user permission list -s | grep -w -q "$app.$permission"
|
yunohost user permission list --short | grep --word-regexp --quiet "$app.$permission"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Redefine the url associated to a permission
|
# Redefine the url associated to a permission
|
||||||
#
|
#
|
||||||
# usage: ynh_permission_url --permission "permission" --url "url"
|
# usage: ynh_permission_url --permission="permission" [--url="url"]
|
||||||
# | arg: permission - the name for the permission (by default a permission named "main" is removed automatically when the app is removed)
|
# | arg: -p, --permission= - the name for the permission (by default a permission named "main" is removed automatically when the app is removed)
|
||||||
# | arg: url - (optional) URL for which access will be allowed/forbidden
|
# | arg: -u, --url= - (optional) URL for which access will be allowed/forbidden
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.7.0 or higher.
|
# Requires YunoHost version 3.7.0 or higher.
|
||||||
ynh_permission_url() {
|
ynh_permission_url() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=pu
|
local legacy_args=pu
|
||||||
declare -Ar args_array=([p]=permission= [u]=url=)
|
local -A args_array=([p]=permission= [u]=url=)
|
||||||
local permission
|
local permission
|
||||||
local url
|
local url
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
url=${url:-}
|
||||||
|
|
||||||
if [[ -n ${url:-} ]]; then
|
if [[ -n $url ]]
|
||||||
|
then
|
||||||
url="'$url'"
|
url="'$url'"
|
||||||
else
|
else
|
||||||
url="None"
|
url="None"
|
||||||
|
@ -260,45 +266,49 @@ ynh_permission_url() {
|
||||||
|
|
||||||
# Update a permission for the app
|
# Update a permission for the app
|
||||||
#
|
#
|
||||||
# usage: ynh_permission_update --permission "permission" --add "group" ["group" ...] --remove "group" ["group" ...]
|
# example: ynh_permission_update --permission admin --add=samdoe --remove=all_users
|
||||||
# | arg: permission - the name for the permission (by default a permission named "main" already exist)
|
#
|
||||||
# | arg: add - the list of group or users to enable add to the permission
|
# usage: ynh_permission_update --permission="permission" [--add="group1 group2"] [--remove="group1 group2"]
|
||||||
# | arg: remove - the list of group or users to remove from the permission
|
# | arg: -p, --permission= - the name for the permission (by default a permission named "main" already exist)
|
||||||
|
# | arg: -a, --add= - the list of group or users to enable add to the permission
|
||||||
|
# | arg: -r, --remove= - the list of group or users to remove from the permission
|
||||||
#
|
#
|
||||||
# example: ynh_permission_update --permission admin --add samdoe --remove all_users
|
|
||||||
# Requires YunoHost version 3.7.0 or higher.
|
# Requires YunoHost version 3.7.0 or higher.
|
||||||
ynh_permission_update() {
|
ynh_permission_update() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=par
|
local legacy_args=par
|
||||||
declare -Ar args_array=( [p]=permission= [a]=add= [r]=remove= )
|
local -A args_array=( [p]=permission= [a]=add= [r]=remove= )
|
||||||
local permission
|
local permission
|
||||||
local add
|
local add
|
||||||
local remove
|
local remove
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
add=${add:-}
|
||||||
|
remove=${remove:-}
|
||||||
|
|
||||||
if [[ -n ${add:-} ]]; then
|
if [[ -n $add ]]; then
|
||||||
add="--add ${add//';'/" "}"
|
add="--add ${add//';'/" "}"
|
||||||
fi
|
fi
|
||||||
if [[ -n ${remove:-} ]]; then
|
if [[ -n $remove ]]; then
|
||||||
remove="--remove ${remove//';'/" "} "
|
remove="--remove ${remove//';'/" "} "
|
||||||
fi
|
fi
|
||||||
|
|
||||||
yunohost user permission update "$app.$permission" ${add:-} ${remove:-}
|
yunohost user permission update "$app.$permission" $add $remove
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check if a permission exists
|
# Check if a permission has an user
|
||||||
#
|
|
||||||
# usage: ynh_permission_has_user --permission=permission --user=user
|
|
||||||
# | arg: -p, --permission - the permission to check
|
|
||||||
# | arg: -u, --user - the user seek in the permission
|
|
||||||
#
|
#
|
||||||
# example: ynh_permission_has_user --permission=main --user=visitors
|
# example: ynh_permission_has_user --permission=main --user=visitors
|
||||||
#
|
#
|
||||||
|
# usage: ynh_permission_has_user --permission=permission --user=user
|
||||||
|
# | arg: -p, --permission= - the permission to check
|
||||||
|
# | arg: -u, --user= - the user seek in the permission
|
||||||
|
# | exit: Return 1 if the permission doesn't have that user or doesn't exist, 0 otherwise
|
||||||
|
#
|
||||||
# Requires YunoHost version 3.7.1 or higher.
|
# Requires YunoHost version 3.7.1 or higher.
|
||||||
ynh_permission_has_user() {
|
ynh_permission_has_user() {
|
||||||
local legacy_args=pu
|
local legacy_args=pu
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
declare -Ar args_array=( [p]=permission= [u]=user= )
|
local -A args_array=( [p]=permission= [u]=user= )
|
||||||
local permission
|
local permission
|
||||||
local user
|
local user
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -309,5 +319,5 @@ ynh_permission_has_user() {
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
yunohost user permission info "$app.$permission" | grep -w -q "$user"
|
yunohost user permission info "$app.$permission" | grep --word-regexp --quiet "$user"
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,29 +5,30 @@
|
||||||
# example: pwd=$(ynh_string_random --length=8)
|
# example: pwd=$(ynh_string_random --length=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)
|
||||||
|
# | ret: the generated string
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.2.4 or higher.
|
# 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
|
||||||
declare -Ar args_array=( [l]=length= )
|
local -A args_array=( [l]=length= )
|
||||||
local length
|
local length
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
length=${length:-24}
|
length=${length:-24}
|
||||||
|
|
||||||
dd if=/dev/urandom bs=1 count=1000 2> /dev/null \
|
dd if=/dev/urandom bs=1 count=1000 2> /dev/null \
|
||||||
| tr -c -d 'A-Za-z0-9' \
|
| tr --complement --delete 'A-Za-z0-9' \
|
||||||
| sed -n 's/\(.\{'"$length"'\}\).*/\1/p'
|
| sed --quiet 's/\(.\{'"$length"'\}\).*/\1/p'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Substitute/replace a string (or expression) by another in a file
|
# Substitute/replace a string (or expression) by another in a file
|
||||||
#
|
#
|
||||||
# usage: ynh_replace_string --match_string=match_string --replace_string=replace_string --target_file=target_file
|
# usage: ynh_replace_string --match_string=match_string --replace_string=replace_string --target_file=target_file
|
||||||
# | arg: -m, --match_string - String to be searched and replaced in the file
|
# | arg: -m, --match_string= - String to be searched and replaced in the file
|
||||||
# | arg: -r, --replace_string - String that will replace matches
|
# | arg: -r, --replace_string= - String that will replace matches
|
||||||
# | arg: -f, --target_file - File in which the string will be replaced.
|
# | arg: -f, --target_file= - File in which the string will be replaced.
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
@ -37,7 +38,7 @@ ynh_string_random() {
|
||||||
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
|
||||||
declare -Ar args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= )
|
local -A args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= )
|
||||||
local match_string
|
local match_string
|
||||||
local replace_string
|
local replace_string
|
||||||
local target_file
|
local target_file
|
||||||
|
@ -55,9 +56,9 @@ ynh_replace_string () {
|
||||||
# Substitute/replace a special string by another in a file
|
# Substitute/replace a special string by another in a file
|
||||||
#
|
#
|
||||||
# usage: ynh_replace_special_string --match_string=match_string --replace_string=replace_string --target_file=target_file
|
# usage: ynh_replace_special_string --match_string=match_string --replace_string=replace_string --target_file=target_file
|
||||||
# | arg: -m, --match_string - String to be searched and replaced in the file
|
# | arg: -m, --match_string= - String to be searched and replaced in the file
|
||||||
# | arg: -r, --replace_string - String that will replace matches
|
# | arg: -r, --replace_string= - String that will replace matches
|
||||||
# | arg: -t, --target_file - File in which the string will be replaced.
|
# | arg: -t, --target_file= - File in which the string will be replaced.
|
||||||
#
|
#
|
||||||
# This helper will use ynh_replace_string, but as you can use special
|
# 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.
|
||||||
|
@ -66,7 +67,7 @@ ynh_replace_string () {
|
||||||
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
|
||||||
declare -Ar args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= )
|
local -A args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= )
|
||||||
local match_string
|
local match_string
|
||||||
local replace_string
|
local replace_string
|
||||||
local target_file
|
local target_file
|
||||||
|
@ -90,14 +91,14 @@ ynh_replace_special_string () {
|
||||||
# example: dbname=$(ynh_sanitize_dbid $app)
|
# example: dbname=$(ynh_sanitize_dbid $app)
|
||||||
#
|
#
|
||||||
# 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.
|
# 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
|
||||||
declare -Ar args_array=( [n]=db_name= )
|
local -A args_array=( [n]=db_name= )
|
||||||
local db_name
|
local db_name
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -108,6 +109,8 @@ ynh_sanitize_dbid () {
|
||||||
|
|
||||||
# Normalize the url path syntax
|
# Normalize the url path syntax
|
||||||
#
|
#
|
||||||
|
# [internal]
|
||||||
|
#
|
||||||
# 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
|
||||||
#
|
#
|
||||||
|
@ -119,13 +122,13 @@ ynh_sanitize_dbid () {
|
||||||
# ynh_normalize_url_path / # -> /
|
# 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.
|
# 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
|
||||||
declare -Ar args_array=( [p]=path_url= )
|
local -A args_array=( [p]=path_url= )
|
||||||
local path_url
|
local path_url
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
# Create a dedicated systemd config
|
# Create a dedicated systemd config
|
||||||
#
|
#
|
||||||
# usage: ynh_add_systemd_config [--service=service] [--template=template]
|
# usage: ynh_add_systemd_config [--service=service] [--template=template]
|
||||||
# | arg: -s, --service - Service name (optionnal, $app by default)
|
# | arg: -s, --service= - Service name (optionnal, $app by default)
|
||||||
# | arg: -t, --template - Name of template file (optionnal, this is 'systemd' by default, meaning ./conf/systemd.service will be used as template)
|
# | arg: -t, --template= - Name of template file (optionnal, this is 'systemd' by default, meaning ./conf/systemd.service will be used as template)
|
||||||
#
|
#
|
||||||
# This will use the template ../conf/<templatename>.service
|
# This will use the template ../conf/<templatename>.service
|
||||||
# to generate a systemd config, by replacing the following keywords
|
# to generate a systemd config, by replacing the following keywords
|
||||||
|
@ -14,11 +14,11 @@
|
||||||
# __APP__ by $app
|
# __APP__ by $app
|
||||||
# __FINALPATH__ by $final_path
|
# __FINALPATH__ by $final_path
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.7.2 or higher.
|
# Requires YunoHost version 2.7.11 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
|
||||||
declare -Ar args_array=( [s]=service= [t]=template= )
|
local -A args_array=( [s]=service= [t]=template= )
|
||||||
local service
|
local service
|
||||||
local template
|
local template
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -32,10 +32,10 @@ ynh_add_systemd_config () {
|
||||||
|
|
||||||
# To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable.
|
# To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable.
|
||||||
# Substitute in a nginx config file only if the variable is not empty
|
# Substitute in a nginx config file only if the variable is not empty
|
||||||
if test -n "${final_path:-}"; then
|
if [ -n "${final_path:-}" ]; then
|
||||||
ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalsystemdconf"
|
ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalsystemdconf"
|
||||||
fi
|
fi
|
||||||
if test -n "${app:-}"; then
|
if [ -n "${app:-}" ]; then
|
||||||
ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="$finalsystemdconf"
|
ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="$finalsystemdconf"
|
||||||
fi
|
fi
|
||||||
ynh_store_file_checksum --file="$finalsystemdconf"
|
ynh_store_file_checksum --file="$finalsystemdconf"
|
||||||
|
@ -48,20 +48,21 @@ ynh_add_systemd_config () {
|
||||||
# Remove the dedicated systemd config
|
# Remove the dedicated 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.
|
# 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
|
||||||
declare -Ar args_array=( [s]=service= )
|
local -A args_array=( [s]=service= )
|
||||||
local service
|
local service
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
local service="${service:-$app}"
|
local service="${service:-$app}"
|
||||||
|
|
||||||
local finalsystemdconf="/etc/systemd/system/$service.service"
|
local finalsystemdconf="/etc/systemd/system/$service.service"
|
||||||
if [ -e "$finalsystemdconf" ]; then
|
if [ -e "$finalsystemdconf" ]
|
||||||
|
then
|
||||||
ynh_systemd_action --service_name=$service --action=stop
|
ynh_systemd_action --service_name=$service --action=stop
|
||||||
systemctl disable $service
|
systemctl disable $service
|
||||||
ynh_secure_remove --file="$finalsystemdconf"
|
ynh_secure_remove --file="$finalsystemdconf"
|
||||||
|
@ -71,46 +72,48 @@ ynh_remove_systemd_config () {
|
||||||
|
|
||||||
# Start (or other actions) a service, print a log in case of failure and optionnaly wait until the service is completely started
|
# Start (or other actions) a service, print a log in case of failure and optionnaly wait until the service is completely started
|
||||||
#
|
#
|
||||||
# usage: ynh_systemd_action [-n service_name] [-a action] [ [-l "line to match"] [-p log_path] [-t timeout] [-e length] ]
|
# usage: ynh_systemd_action [--service_name=service_name] [--action=action] [ [--line_match="line to match"] [--log_path=log_path] [--timeout=300] [--length=20] ]
|
||||||
# | arg: -n, --service_name= - Name of the service to start. Default : $app
|
# | arg: -n, --service_name= - Name of the service to start. Default : $app
|
||||||
# | arg: -a, --action= - Action to perform with systemctl. Default: start
|
# | 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: -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: -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: -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
|
# | arg: -e, --length= - Length of the error log : Default : 20
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_systemd_action() {
|
ynh_systemd_action() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=nalpte
|
local legacy_args=nalpte
|
||||||
declare -Ar args_array=( [n]=service_name= [a]=action= [l]=line_match= [p]=log_path= [t]=timeout= [e]=length= )
|
local -A args_array=( [n]=service_name= [a]=action= [l]=line_match= [p]=log_path= [t]=timeout= [e]=length= )
|
||||||
local service_name
|
local service_name
|
||||||
local action
|
local action
|
||||||
local line_match
|
local line_match
|
||||||
local length
|
local length
|
||||||
local log_path
|
local log_path
|
||||||
local timeout
|
local timeout
|
||||||
|
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
service_name="${service_name:-$app}"
|
||||||
local service_name="${service_name:-$app}"
|
action=${action:-start}
|
||||||
local action=${action:-start}
|
line_match=${line_match:-}
|
||||||
local log_path="${log_path:-/var/log/$service_name/$service_name.log}"
|
length=${length:-20}
|
||||||
local length=${length:-20}
|
log_path="${log_path:-/var/log/$service_name/$service_name.log}"
|
||||||
local timeout=${timeout:-300}
|
timeout=${timeout:-300}
|
||||||
|
|
||||||
# Start to read the log
|
# Start to read the log
|
||||||
if [[ -n "${line_match:-}" ]]
|
if [[ -n "$line_match" ]]
|
||||||
then
|
then
|
||||||
local templog="$(mktemp)"
|
local templog="$(mktemp)"
|
||||||
# Following the starting of the app in its log
|
# Following the starting of the app in its log
|
||||||
if [ "$log_path" == "systemd" ] ; then
|
if [ "$log_path" == "systemd" ]
|
||||||
|
then
|
||||||
# Read the systemd journal
|
# Read the systemd journal
|
||||||
journalctl --unit=$service_name --follow --since=-0 --quiet > "$templog" &
|
journalctl --unit=$service_name --follow --since=-0 --quiet > "$templog" &
|
||||||
# Get the PID of the journalctl command
|
# Get the PID of the journalctl command
|
||||||
local pid_tail=$!
|
local pid_tail=$!
|
||||||
else
|
else
|
||||||
# Read the specified log file
|
# Read the specified log file
|
||||||
tail -F -n0 "$log_path" > "$templog" 2>&1 &
|
tail --follow=name --retry --lines=0 "$log_path" > "$templog" 2>&1 &
|
||||||
# Get the PID of the tail command
|
# Get the PID of the tail command
|
||||||
local pid_tail=$!
|
local pid_tail=$!
|
||||||
fi
|
fi
|
||||||
|
@ -121,10 +124,20 @@ ynh_systemd_action() {
|
||||||
action="reload-or-restart"
|
action="reload-or-restart"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
systemctl $action $service_name \
|
# If the service fails to perform the action
|
||||||
|| ( journalctl --no-pager --lines=$length -u $service_name >&2 \
|
if ! systemctl $action $service_name
|
||||||
; test -e "$log_path" && echo "--" >&2 && tail --lines=$length "$log_path" >&2 \
|
then
|
||||||
; false )
|
# Show syslog for this service
|
||||||
|
ynh_exec_err journalctl --no-pager --lines=$length --unit=$service_name
|
||||||
|
# If a log is specified for this service, show also the content of this log
|
||||||
|
if [ -e "$log_path" ]
|
||||||
|
then
|
||||||
|
ynh_print_err --message="--"
|
||||||
|
ynh_exec_err tail --lines=$length "$log_path"
|
||||||
|
fi
|
||||||
|
# Fail the app script, since the service failed.
|
||||||
|
ynh_die
|
||||||
|
fi
|
||||||
|
|
||||||
# Start the timeout and try to find line_match
|
# Start the timeout and try to find line_match
|
||||||
if [[ -n "${line_match:-}" ]]
|
if [[ -n "${line_match:-}" ]]
|
||||||
|
@ -133,7 +146,7 @@ ynh_systemd_action() {
|
||||||
for i in $(seq 1 $timeout)
|
for i in $(seq 1 $timeout)
|
||||||
do
|
do
|
||||||
# Read the log until the sentence is found, that means the app finished to start. Or run until the timeout
|
# Read the log until the sentence is found, that means the app finished to start. Or run until the timeout
|
||||||
if grep --quiet "$line_match" "$templog"
|
if grep --extended-regexp --quiet "$line_match" "$templog"
|
||||||
then
|
then
|
||||||
ynh_print_info --message="The service $service_name has correctly executed the action ${action}."
|
ynh_print_info --message="The service $service_name has correctly executed the action ${action}."
|
||||||
break
|
break
|
||||||
|
@ -153,8 +166,12 @@ ynh_systemd_action() {
|
||||||
then
|
then
|
||||||
ynh_print_warn --message="The service $service_name didn't fully executed the action ${action} before the timeout."
|
ynh_print_warn --message="The service $service_name didn't fully executed the action ${action} before the timeout."
|
||||||
ynh_print_warn --message="Please find here an extract of the end of the log of the service $service_name:"
|
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
|
ynh_exec_warn journalctl --no-pager --lines=$length --unit=$service_name
|
||||||
test -e "$log_path" && echo "--" >&2 && tail --lines=$length "$log_path" >&2
|
if [ -e "$log_path" ]
|
||||||
|
then
|
||||||
|
ynh_print_warn --message="\-\-\-"
|
||||||
|
ynh_exec_warn tail --lines=$length "$log_path"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
ynh_clean_check_starting
|
ynh_clean_check_starting
|
||||||
fi
|
fi
|
||||||
|
@ -164,11 +181,13 @@ ynh_systemd_action() {
|
||||||
# (usually used in ynh_clean_setup scripts)
|
# (usually used in ynh_clean_setup scripts)
|
||||||
#
|
#
|
||||||
# usage: ynh_clean_check_starting
|
# usage: ynh_clean_check_starting
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_clean_check_starting () {
|
ynh_clean_check_starting () {
|
||||||
if [ -n "$pid_tail" ]
|
if [ -n "$pid_tail" ]
|
||||||
then
|
then
|
||||||
# Stop the execution of tail.
|
# Stop the execution of tail.
|
||||||
kill -s 15 $pid_tail 2>&1
|
kill -SIGTERM $pid_tail 2>&1
|
||||||
fi
|
fi
|
||||||
if [ -n "$templog" ]
|
if [ -n "$templog" ]
|
||||||
then
|
then
|
||||||
|
@ -176,4 +195,3 @@ ynh_clean_check_starting () {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,18 +5,19 @@
|
||||||
# example: ynh_user_exists 'toto' || exit 1
|
# example: ynh_user_exists 'toto' || exit 1
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
# | exit: Return 1 if the user doesn't exist, 0 otherwise
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.2.4 or higher.
|
# 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
|
||||||
declare -Ar args_array=( [u]=username= )
|
local -A args_array=( [u]=username= )
|
||||||
local username
|
local username
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
yunohost user list --output-as json | grep -q "\"username\": \"${username}\""
|
yunohost user list --output-as json | grep --quiet "\"username\": \"${username}\""
|
||||||
}
|
}
|
||||||
|
|
||||||
# Retrieve a YunoHost user information
|
# Retrieve a YunoHost user information
|
||||||
|
@ -24,15 +25,15 @@ ynh_user_exists() {
|
||||||
# example: mail=$(ynh_user_get_info 'toto' 'mail')
|
# example: mail=$(ynh_user_get_info 'toto' 'mail')
|
||||||
#
|
#
|
||||||
# usage: ynh_user_get_info --username=username --key=key
|
# usage: ynh_user_get_info --username=username --key=key
|
||||||
# | 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.
|
# 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
|
||||||
declare -Ar args_array=( [u]=username= [k]=key= )
|
local -A args_array=( [u]=username= [k]=key= )
|
||||||
local username
|
local username
|
||||||
local key
|
local key
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -57,13 +58,14 @@ ynh_user_list() {
|
||||||
# Check if a user exists on the system
|
# Check if a user exists on the system
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
# | exit: Return 1 if the user doesn't exist, 0 otherwise
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.2.4 or higher.
|
# 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
|
||||||
declare -Ar args_array=( [u]=username= )
|
local -A args_array=( [u]=username= )
|
||||||
local username
|
local username
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -74,11 +76,14 @@ ynh_system_user_exists() {
|
||||||
# Check if a group exists on the system
|
# Check if a group exists on the system
|
||||||
#
|
#
|
||||||
# usage: ynh_system_group_exists --group=group
|
# usage: ynh_system_group_exists --group=group
|
||||||
# | arg: -g, --group - the group to check
|
# | arg: -g, --group= - the group to check
|
||||||
|
# | exit: Return 1 if the group doesn't exist, 0 otherwise
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.5.0.2 or higher.
|
||||||
ynh_system_group_exists() {
|
ynh_system_group_exists() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=g
|
local legacy_args=g
|
||||||
declare -Ar args_array=( [g]=group= )
|
local -A args_array=( [g]=group= )
|
||||||
local group
|
local group
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -95,15 +100,15 @@ ynh_system_group_exists() {
|
||||||
# ynh_system_user_create --username=discourse --home_dir=/var/www/discourse --use_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. If this argument is omitted, the user will be created with /usr/sbin/nologin shell
|
# | arg: -s, --use_shell - Create a user using the default login shell if present. If this argument is omitted, the user will be created with /usr/sbin/nologin shell
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# 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
|
||||||
declare -Ar args_array=( [u]=username= [h]=home_dir= [s]=use_shell )
|
local -A args_array=( [u]=username= [h]=home_dir= [s]=use_shell )
|
||||||
local username
|
local username
|
||||||
local home_dir
|
local home_dir
|
||||||
local use_shell
|
local use_shell
|
||||||
|
@ -114,30 +119,32 @@ ynh_system_user_create () {
|
||||||
|
|
||||||
if ! ynh_system_user_exists "$username" # Check if the user exists on the system
|
if ! ynh_system_user_exists "$username" # Check if the user exists on the system
|
||||||
then # If the user doesn't exist
|
then # If the user doesn't exist
|
||||||
if [ -n "$home_dir" ]; then # If a home dir is mentioned
|
if [ -n "$home_dir" ]
|
||||||
local user_home_dir="-d $home_dir"
|
then # If a home dir is mentioned
|
||||||
|
local user_home_dir="--home-dir $home_dir"
|
||||||
else
|
else
|
||||||
local user_home_dir="--no-create-home"
|
local user_home_dir="--no-create-home"
|
||||||
fi
|
fi
|
||||||
if [ $use_shell -eq 1 ]; then # If we want a shell for the user
|
if [ $use_shell -eq 1 ]
|
||||||
|
then # If we want a shell for the user
|
||||||
local shell="" # Use default shell
|
local shell="" # Use default shell
|
||||||
else
|
else
|
||||||
local shell="--shell /usr/sbin/nologin"
|
local shell="--shell /usr/sbin/nologin"
|
||||||
fi
|
fi
|
||||||
useradd $user_home_dir --system --user-group $username $shell || ynh_die "Unable to create $username system account"
|
useradd $user_home_dir --system --user-group $username $shell || ynh_die --message="Unable to create $username system account"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Delete a system user
|
# Delete a system user
|
||||||
#
|
#
|
||||||
# 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.
|
# 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
|
||||||
declare -Ar args_array=( [u]=username= )
|
local -A args_array=( [u]=username= )
|
||||||
local username
|
local username
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
|
@ -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
|
||||||
|
@ -23,7 +24,9 @@ ynh_exit_properly () {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
trap '' EXIT # Ignore new exit signals
|
trap '' EXIT # Ignore new exit signals
|
||||||
set +eu # Do not exit anymore if a command fail or if a variable is empty
|
# Do not exit anymore if a command fail or if a variable is empty
|
||||||
|
set +o errexit # set +e
|
||||||
|
set +o nounset # set +u
|
||||||
|
|
||||||
# Small tempo to avoid the next message being mixed up with other DEBUG messages
|
# Small tempo to avoid the next message being mixed up with other DEBUG messages
|
||||||
sleep 0.5
|
sleep 0.5
|
||||||
|
@ -46,12 +49,17 @@ ynh_exit_properly () {
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# 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 -o errexit # set -e; Exit if a command fail
|
||||||
|
set -o nounset # set -u; And if a variable is used unset
|
||||||
trap ynh_exit_properly EXIT # Capturing exit signals on shell script
|
trap ynh_exit_properly EXIT # Capturing exit signals on shell script
|
||||||
}
|
}
|
||||||
|
|
||||||
# Download, check integrity, uncompress and patch the source from app.src
|
# Download, check integrity, uncompress and patch the source from app.src
|
||||||
#
|
#
|
||||||
|
# usage: ynh_setup_source --dest_dir=dest_dir [--source_id=source_id]
|
||||||
|
# | arg: -d, --dest_dir= - Directory where to setup sources
|
||||||
|
# | arg: -s, --source_id= - Name of the app, if the package contains more than one app
|
||||||
|
#
|
||||||
# The file conf/app.src need to contains:
|
# The file conf/app.src need to contains:
|
||||||
#
|
#
|
||||||
# SOURCE_URL=Address to download the app archive
|
# SOURCE_URL=Address to download the app archive
|
||||||
|
@ -90,16 +98,11 @@ ynh_abort_if_errors () {
|
||||||
# Finally, patches named sources/patches/${src_id}-*.patch and extra files in
|
# Finally, patches named sources/patches/${src_id}-*.patch and extra files in
|
||||||
# sources/extra_files/$src_id will be applied to dest_dir
|
# sources/extra_files/$src_id will be applied to dest_dir
|
||||||
#
|
#
|
||||||
#
|
|
||||||
# usage: ynh_setup_source --dest_dir=dest_dir [--source_id=source_id]
|
|
||||||
# | arg: -d, --dest_dir - Directory where to setup sources
|
|
||||||
# | arg: -s, --source_id - Name of the app, if the package contains more than one app
|
|
||||||
#
|
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# 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
|
||||||
declare -Ar args_array=( [d]=dest_dir= [s]=source_id= )
|
local -A args_array=( [d]=dest_dir= [s]=source_id= )
|
||||||
local dest_dir
|
local dest_dir
|
||||||
local source_id
|
local source_id
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -115,13 +118,13 @@ ynh_setup_source () {
|
||||||
|
|
||||||
# Load value from configuration file (see above for a small doc about this file
|
# Load value from configuration file (see above for a small doc about this file
|
||||||
# format)
|
# format)
|
||||||
local src_url=$(grep 'SOURCE_URL=' "$src_file_path" | cut -d= -f2-)
|
local src_url=$(grep 'SOURCE_URL=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||||
local src_sum=$(grep 'SOURCE_SUM=' "$src_file_path" | cut -d= -f2-)
|
local src_sum=$(grep 'SOURCE_SUM=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||||
local src_sumprg=$(grep 'SOURCE_SUM_PRG=' "$src_file_path" | cut -d= -f2-)
|
local src_sumprg=$(grep 'SOURCE_SUM_PRG=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||||
local src_format=$(grep 'SOURCE_FORMAT=' "$src_file_path" | cut -d= -f2-)
|
local src_format=$(grep 'SOURCE_FORMAT=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||||
local src_extract=$(grep 'SOURCE_EXTRACT=' "$src_file_path" | cut -d= -f2-)
|
local src_extract=$(grep 'SOURCE_EXTRACT=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||||
local src_in_subdir=$(grep 'SOURCE_IN_SUBDIR=' "$src_file_path" | cut -d= -f2-)
|
local src_in_subdir=$(grep 'SOURCE_IN_SUBDIR=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||||
local src_filename=$(grep 'SOURCE_FILENAME=' "$src_file_path" | cut -d= -f2-)
|
local src_filename=$(grep 'SOURCE_FILENAME=' "$src_file_path" | cut --delimiter='=' --fields=2-)
|
||||||
|
|
||||||
# Default value
|
# Default value
|
||||||
src_sumprg=${src_sumprg:-sha256sum}
|
src_sumprg=${src_sumprg:-sha256sum}
|
||||||
|
@ -138,15 +141,15 @@ ynh_setup_source () {
|
||||||
then # Use the local source file if it is present
|
then # Use the local source file if it is present
|
||||||
cp $local_src $src_filename
|
cp $local_src $src_filename
|
||||||
else # If not, download the source
|
else # If not, download the source
|
||||||
local out=`wget -nv -O $src_filename $src_url 2>&1` || ynh_print_err --message="$out"
|
local out=`wget --no-verbose --output-document=$src_filename $src_url 2>&1` || ynh_print_err --message="$out"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check the control sum
|
# Check the control sum
|
||||||
echo "${src_sum} ${src_filename}" | ${src_sumprg} -c --status \
|
echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status \
|
||||||
|| ynh_die --message="Corrupt source"
|
|| ynh_die --message="Corrupt source"
|
||||||
|
|
||||||
# Extract source into the app dir
|
# Extract source into the app dir
|
||||||
mkdir -p "$dest_dir"
|
mkdir --parents "$dest_dir"
|
||||||
|
|
||||||
if ! "$src_extract"
|
if ! "$src_extract"
|
||||||
then
|
then
|
||||||
|
@ -155,10 +158,11 @@ ynh_setup_source () {
|
||||||
then
|
then
|
||||||
# Zip format
|
# Zip format
|
||||||
# Using of a temp directory, because unzip doesn't manage --strip-components
|
# Using of a temp directory, because unzip doesn't manage --strip-components
|
||||||
if $src_in_subdir ; then
|
if $src_in_subdir
|
||||||
local tmp_dir=$(mktemp -d)
|
then
|
||||||
|
local tmp_dir=$(mktemp --directory)
|
||||||
unzip -quo $src_filename -d "$tmp_dir"
|
unzip -quo $src_filename -d "$tmp_dir"
|
||||||
cp -a $tmp_dir/*/. "$dest_dir"
|
cp --archive $tmp_dir/*/. "$dest_dir"
|
||||||
ynh_secure_remove --file="$tmp_dir"
|
ynh_secure_remove --file="$tmp_dir"
|
||||||
else
|
else
|
||||||
unzip -quo $src_filename -d "$dest_dir"
|
unzip -quo $src_filename -d "$dest_dir"
|
||||||
|
@ -167,40 +171,39 @@ ynh_setup_source () {
|
||||||
local strip=""
|
local strip=""
|
||||||
if [ "$src_in_subdir" != "false" ]
|
if [ "$src_in_subdir" != "false" ]
|
||||||
then
|
then
|
||||||
if [ "$src_in_subdir" == "true" ]; then
|
if [ "$src_in_subdir" == "true" ]
|
||||||
|
then
|
||||||
local sub_dirs=1
|
local sub_dirs=1
|
||||||
else
|
else
|
||||||
local sub_dirs="$src_in_subdir"
|
local sub_dirs="$src_in_subdir"
|
||||||
fi
|
fi
|
||||||
strip="--strip-components $sub_dirs"
|
strip="--strip-components $sub_dirs"
|
||||||
fi
|
fi
|
||||||
if [[ "$src_format" =~ ^tar.gz|tar.bz2|tar.xz$ ]] ; then
|
if [[ "$src_format" =~ ^tar.gz|tar.bz2|tar.xz$ ]]
|
||||||
tar -xf $src_filename -C "$dest_dir" $strip
|
then
|
||||||
|
tar --extract --file=$src_filename --directory="$dest_dir" $strip
|
||||||
else
|
else
|
||||||
ynh_die --message="Archive format unrecognized."
|
ynh_die --message="Archive format unrecognized."
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Apply patches
|
# Apply patches
|
||||||
if (( $(find $YNH_CWD/../sources/patches/ -type f -name "${source_id}-*.patch" 2> /dev/null | wc -l) > "0" )); then
|
if (( $(find $YNH_CWD/../sources/patches/ -type f -name "${source_id}-*.patch" 2> /dev/null | wc --lines) > "0" ))
|
||||||
local old_dir=$(pwd)
|
then
|
||||||
(cd "$dest_dir" \
|
(cd "$dest_dir"
|
||||||
&& for p in $YNH_CWD/../sources/patches/${source_id}-*.patch; do \
|
for p in $YNH_CWD/../sources/patches/${source_id}-*.patch
|
||||||
patch -p1 < $p; done) \
|
do
|
||||||
|| ynh_die --message="Unable to apply patches"
|
patch --strip=1 < $p
|
||||||
cd $old_dir
|
done) || ynh_die --message="Unable to apply patches"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Add supplementary files
|
# Add supplementary files
|
||||||
if test -e "$YNH_CWD/../sources/extra_files/${source_id}"; then
|
if test -e "$YNH_CWD/../sources/extra_files/${source_id}"; then
|
||||||
cp -a $YNH_CWD/../sources/extra_files/$source_id/. "$dest_dir"
|
cp --archive $YNH_CWD/../sources/extra_files/$source_id/. "$dest_dir"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Curl abstraction to help with POST requests to local pages (such as installation forms)
|
# Curl abstraction to help with POST requests to local pages (such as installation forms)
|
||||||
# For multiple calls, cookies are persisted between each call for the same app
|
|
||||||
#
|
|
||||||
# $domain and $path_url should be defined externally (and correspond to the domain.tld and the /path (of the app?))
|
|
||||||
#
|
#
|
||||||
# example: ynh_local_curl "/install.php?installButton" "foo=$var1" "bar=$var2"
|
# example: ynh_local_curl "/install.php?installButton" "foo=$var1" "bar=$var2"
|
||||||
#
|
#
|
||||||
|
@ -210,6 +213,10 @@ ynh_setup_source () {
|
||||||
# | 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
|
||||||
#
|
#
|
||||||
|
# For multiple calls, cookies are persisted between each call for the same app
|
||||||
|
#
|
||||||
|
# $domain and $path_url should be defined externally (and correspond to the domain.tld and the /path (of the app?))
|
||||||
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# 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
|
||||||
|
@ -244,11 +251,13 @@ ynh_local_curl () {
|
||||||
chmod 700 $cookiefile
|
chmod 700 $cookiefile
|
||||||
|
|
||||||
# Curl the URL
|
# Curl the URL
|
||||||
curl --silent --show-error -kL -H "Host: $domain" --resolve $domain:443:127.0.0.1 $POST_data "$full_page_url" --cookie-jar $cookiefile --cookie $cookiefile
|
curl --silent --show-error --insecure --location --header "Host: $domain" --resolve $domain:443:127.0.0.1 $POST_data "$full_page_url" --cookie-jar $cookiefile --cookie $cookiefile
|
||||||
}
|
}
|
||||||
|
|
||||||
# Render templates with Jinja2
|
# Render templates with Jinja2
|
||||||
#
|
#
|
||||||
|
# [internal]
|
||||||
|
#
|
||||||
# Attention : Variables should be exported before calling this helper to be
|
# Attention : Variables should be exported before calling this helper to be
|
||||||
# accessible inside templates.
|
# accessible inside templates.
|
||||||
#
|
#
|
||||||
|
@ -287,7 +296,7 @@ ynh_mkdir_tmp() {
|
||||||
ynh_print_warn --message="The helper ynh_mkdir_tmp is deprecated."
|
ynh_print_warn --message="The helper ynh_mkdir_tmp is deprecated."
|
||||||
ynh_print_warn --message="You should use 'mktemp -d' instead and manage permissions \
|
ynh_print_warn --message="You should use 'mktemp -d' instead and manage permissions \
|
||||||
properly with chmod/chown."
|
properly with chmod/chown."
|
||||||
local TMP_DIR=$(mktemp -d)
|
local TMP_DIR=$(mktemp --directory)
|
||||||
|
|
||||||
# Give rights to other users could be a security risk.
|
# Give rights to other users could be a security risk.
|
||||||
# But for retrocompatibility we need it. (This helpers is deprecated)
|
# But for retrocompatibility we need it. (This helpers is deprecated)
|
||||||
|
@ -298,13 +307,13 @@ properly with chmod/chown."
|
||||||
# Remove a file or a directory securely
|
# Remove a file or a directory securely
|
||||||
#
|
#
|
||||||
# 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.
|
# 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
|
||||||
declare -Ar args_array=( [f]=file= )
|
local -A args_array=( [f]=file= )
|
||||||
local file
|
local file
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -321,7 +330,7 @@ ynh_secure_remove () {
|
||||||
if [[ -z "$file" ]]
|
if [[ -z "$file" ]]
|
||||||
then
|
then
|
||||||
ynh_print_warn --message="ynh_secure_remove called with empty argument, ignoring."
|
ynh_print_warn --message="ynh_secure_remove called with empty argument, ignoring."
|
||||||
else if [[ "$forbidden_path" =~ "$file" \
|
elif [[ "$forbidden_path" =~ "$file" \
|
||||||
# Match all paths or subpaths in $forbidden_path
|
# Match all paths or subpaths in $forbidden_path
|
||||||
|| "$file" =~ ^/[[:alnum:]]+$ \
|
|| "$file" =~ ^/[[:alnum:]]+$ \
|
||||||
# Match all first level paths from / (Like /var, /root, etc...)
|
# Match all first level paths from / (Like /var, /root, etc...)
|
||||||
|
@ -329,16 +338,18 @@ ynh_secure_remove () {
|
||||||
# Match if the path finishes by /. Because it seems there is an empty variable
|
# Match if the path finishes by /. Because it seems there is an empty variable
|
||||||
then
|
then
|
||||||
ynh_print_warn --message="Not deleting '$file' because it is not an acceptable path to delete."
|
ynh_print_warn --message="Not deleting '$file' because it is not an acceptable path to delete."
|
||||||
else if [ -e "$file" ]
|
elif [ -e "$file" ]
|
||||||
then
|
then
|
||||||
rm -R "$file"
|
rm --recursive "$file"
|
||||||
else
|
else
|
||||||
ynh_print_info --message="'$file' wasn't deleted because it doesn't exist."
|
ynh_print_info --message="'$file' wasn't deleted because it doesn't exist."
|
||||||
fi fi fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Extract a key from a plain command output
|
# Extract a key from a plain command output
|
||||||
#
|
#
|
||||||
|
# [internal]
|
||||||
|
#
|
||||||
# example: yunohost user info tata --output-as plain | ynh_get_plain_key mail
|
# example: yunohost user info tata --output-as plain | ynh_get_plain_key mail
|
||||||
#
|
#
|
||||||
# usage: ynh_get_plain_key key [subkey [subsubkey ...]]
|
# usage: ynh_get_plain_key key [subkey [subsubkey ...]]
|
||||||
|
@ -352,12 +363,16 @@ ynh_get_plain_key() {
|
||||||
# an info to be redacted by the core
|
# an info to be redacted by the core
|
||||||
local key_=$1
|
local key_=$1
|
||||||
shift
|
shift
|
||||||
while read line; do
|
while read line
|
||||||
if [[ "$founded" == "1" ]] ; then
|
do
|
||||||
|
if [[ "$founded" == "1" ]]
|
||||||
|
then
|
||||||
[[ "$line" =~ ^${prefix}[^#] ]] && return
|
[[ "$line" =~ ^${prefix}[^#] ]] && return
|
||||||
echo $line
|
echo $line
|
||||||
elif [[ "$line" =~ ^${prefix}${key_}$ ]]; then
|
elif [[ "$line" =~ ^${prefix}${key_}$ ]]
|
||||||
if [[ -n "${1:-}" ]]; then
|
then
|
||||||
|
if [[ -n "${1:-}" ]]
|
||||||
|
then
|
||||||
prefix+="#"
|
prefix+="#"
|
||||||
key_=$1
|
key_=$1
|
||||||
shift
|
shift
|
||||||
|
@ -370,15 +385,16 @@ ynh_get_plain_key() {
|
||||||
|
|
||||||
# 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="manifest.json" --key="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
|
||||||
|
# | ret: the value associate to that key
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 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
|
local legacy_args=mk
|
||||||
declare -Ar args_array=( [m]=manifest= [k]=manifest_key= )
|
local -A args_array=( [m]=manifest= [k]=manifest_key= )
|
||||||
local manifest
|
local manifest
|
||||||
local manifest_key
|
local manifest_key
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -394,48 +410,50 @@ ynh_read_manifest () {
|
||||||
|
|
||||||
# Read the upstream version from the manifest
|
# Read the upstream version from the manifest
|
||||||
#
|
#
|
||||||
|
# usage: ynh_app_upstream_version [--manifest="manifest.json"]
|
||||||
|
# | arg: -m, --manifest= - Path of the manifest to read
|
||||||
|
# | ret: the version number of the upstream app
|
||||||
|
#
|
||||||
# The version number in the manifest is defined by <upstreamversion>~ynh<packageversion>
|
# The version number in the manifest is defined by <upstreamversion>~ynh<packageversion>
|
||||||
# For example : 4.3-2~ynh3
|
# For example : 4.3-2~ynh3
|
||||||
# This include the number before ~ynh
|
# This include the number before ~ynh
|
||||||
# In the last example it return 4.3-2
|
# In the last example it return 4.3-2
|
||||||
#
|
#
|
||||||
# usage: ynh_app_upstream_version [-m manifest]
|
|
||||||
# | arg: -m, --manifest= - Path of the manifest to read
|
|
||||||
#
|
|
||||||
# Requires YunoHost version 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_app_upstream_version () {
|
ynh_app_upstream_version () {
|
||||||
# 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
|
||||||
declare -Ar args_array=( [m]=manifest= )
|
local -A args_array=( [m]=manifest= )
|
||||||
local manifest
|
local manifest
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
manifest="${manifest:-../manifest.json}"
|
manifest="${manifest:-../manifest.json}"
|
||||||
|
|
||||||
version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
|
version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
|
||||||
echo "${version_key/~ynh*/}"
|
echo "${version_key/~ynh*/}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Read package version from the manifest
|
# Read package version from the manifest
|
||||||
#
|
#
|
||||||
|
# usage: ynh_app_package_version [--manifest="manifest.json"]
|
||||||
|
# | arg: -m, --manifest= - Path of the manifest to read
|
||||||
|
# | ret: the version number of the package
|
||||||
|
#
|
||||||
# The version number in the manifest is defined by <upstreamversion>~ynh<packageversion>
|
# The version number in the manifest is defined by <upstreamversion>~ynh<packageversion>
|
||||||
# For example : 4.3-2~ynh3
|
# For example : 4.3-2~ynh3
|
||||||
# This include the number after ~ynh
|
# This include the number after ~ynh
|
||||||
# In the last example it return 3
|
# In the last example it return 3
|
||||||
#
|
#
|
||||||
# usage: ynh_app_package_version [-m manifest]
|
|
||||||
# | arg: -m, --manifest= - Path of the manifest to read
|
|
||||||
#
|
|
||||||
# Requires YunoHost version 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_app_package_version () {
|
ynh_app_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=m
|
local legacy_args=m
|
||||||
declare -Ar args_array=( [m]=manifest= )
|
local -A args_array=( [m]=manifest= )
|
||||||
local manifest
|
local manifest
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
manifest="${manifest:-../manifest.json}"
|
manifest="${manifest:-../manifest.json}"
|
||||||
|
|
||||||
version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
|
version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
|
||||||
echo "${version_key/*~ynh/}"
|
echo "${version_key/*~ynh/}"
|
||||||
}
|
}
|
||||||
|
@ -469,7 +487,8 @@ ynh_check_app_version_changed () {
|
||||||
local update_version=$(ynh_read_manifest --manifest="../manifest.json" --manifest_key="version" || echo 1.0)
|
local update_version=$(ynh_read_manifest --manifest="../manifest.json" --manifest_key="version" || echo 1.0)
|
||||||
local update_upstream_version="$(ynh_app_upstream_version)"
|
local update_upstream_version="$(ynh_app_upstream_version)"
|
||||||
|
|
||||||
if [ "$current_version" == "$update_version" ] ; then
|
if [ "$current_version" == "$update_version" ]
|
||||||
|
then
|
||||||
# Complete versions are the same
|
# Complete versions are the same
|
||||||
if [ "$force_upgrade" != "0" ]
|
if [ "$force_upgrade" != "0" ]
|
||||||
then
|
then
|
||||||
|
@ -481,7 +500,8 @@ ynh_check_app_version_changed () {
|
||||||
else
|
else
|
||||||
ynh_die "Up-to-date, nothing to do" 0
|
ynh_die "Up-to-date, nothing to do" 0
|
||||||
fi
|
fi
|
||||||
elif [ "$current_upstream_version" == "$update_upstream_version" ] ; then
|
elif [ "$current_upstream_version" == "$update_upstream_version" ]
|
||||||
|
then
|
||||||
# Upstream versions are the same, only YunoHost package versions differ
|
# Upstream versions are the same, only YunoHost package versions differ
|
||||||
return_value="UPGRADE_PACKAGE"
|
return_value="UPGRADE_PACKAGE"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -43,16 +43,16 @@ do_post_regen() {
|
||||||
|
|
||||||
# retrieve variables
|
# retrieve variables
|
||||||
main_domain=$(cat /etc/yunohost/current_host)
|
main_domain=$(cat /etc/yunohost/current_host)
|
||||||
domain_list=$(yunohost domain list --output-as plain --quiet)
|
domain_list=$(yunohost domain list --exclude-subdomains --output-as plain --quiet)
|
||||||
|
|
||||||
# create metronome directories for domains
|
# create metronome directories for domains
|
||||||
for domain in $domain_list; do
|
for domain in $domain_list; do
|
||||||
mkdir -p "/var/lib/metronome/${domain//./%2e}/pep"
|
mkdir -p "/var/lib/metronome/${domain//./%2e}/pep"
|
||||||
done
|
|
||||||
# http_upload directory must be writable by metronome and readable by nginx
|
# http_upload directory must be writable by metronome and readable by nginx
|
||||||
mkdir -p "/var/xmpp-upload/${main_domain}/upload"
|
mkdir -p "/var/xmpp-upload/${domain}/upload"
|
||||||
chmod g+s "/var/xmpp-upload/${main_domain}/upload"
|
chmod g+s "/var/xmpp-upload/${domain}/upload"
|
||||||
chown -R metronome:www-data "/var/xmpp-upload/${main_domain}"
|
chown -R metronome:www-data "/var/xmpp-upload/${domain}"
|
||||||
|
done
|
||||||
|
|
||||||
# fix some permissions
|
# fix some permissions
|
||||||
chown -R metronome: /var/lib/metronome/
|
chown -R metronome: /var/lib/metronome/
|
||||||
|
|
|
@ -27,7 +27,8 @@ do_init_regen() {
|
||||||
ynh_render_template "yunohost_admin.conf" "${nginx_conf_dir}/yunohost_admin.conf"
|
ynh_render_template "yunohost_admin.conf" "${nginx_conf_dir}/yunohost_admin.conf"
|
||||||
|
|
||||||
# Restart nginx if conf looks good, otherwise display error and exit unhappy
|
# Restart nginx if conf looks good, otherwise display error and exit unhappy
|
||||||
nginx -t 2>/dev/null && service nginx restart || (nginx -t && exit 1)
|
nginx -t 2>/dev/null || { nginx -t; exit 1; }
|
||||||
|
systemctl restart nginx || { journalctl --no-pager --lines=10 -u nginx >&2; exit 1; }
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
@ -125,9 +126,9 @@ do_post_regen() {
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Reload nginx if conf looks good, otherwise display error and exit unhappy
|
||||||
# Reload nginx configuration
|
nginx -t 2>/dev/null || { nginx -t; exit 1; }
|
||||||
pgrep nginx && service nginx reload
|
pgrep nginx && systemctl reload nginx || { journalctl --no-pager --lines=10 -u nginx >&2; exit 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE=${2:-0}
|
FORCE=${2:-0}
|
||||||
|
|
|
@ -35,7 +35,8 @@ do_pre_regen() {
|
||||||
> "${default_dir}/postsrsd"
|
> "${default_dir}/postsrsd"
|
||||||
|
|
||||||
# adapt it for IPv4-only hosts
|
# adapt it for IPv4-only hosts
|
||||||
if [ ! -f /proc/net/if_inet6 ]; then
|
ipv6="$(yunohost settings get 'smtp.allow_ipv6')"
|
||||||
|
if [ "$ipv6" == "False" ] || [ ! -f /proc/net/if_inet6 ]; then
|
||||||
sed -i \
|
sed -i \
|
||||||
's/ \[::ffff:127.0.0.0\]\/104 \[::1\]\/128//g' \
|
's/ \[::ffff:127.0.0.0\]\/104 \[::1\]\/128//g' \
|
||||||
"${postfix_dir}/main.cf"
|
"${postfix_dir}/main.cf"
|
||||||
|
|
|
@ -50,6 +50,21 @@ do_pre_regen() {
|
||||||
do_post_regen() {
|
do_post_regen() {
|
||||||
regen_conf_files=$1
|
regen_conf_files=$1
|
||||||
|
|
||||||
|
# Fuck it, those domain/search entries from dhclient are usually annoying
|
||||||
|
# lying shit from the ISP trying to MiTM
|
||||||
|
if grep -q -E "^ *(domain|search)" /run/resolvconf/resolv.conf
|
||||||
|
then
|
||||||
|
if grep -q -E "^ *(domain|search)" /run/resolvconf/interface/*.dhclient 2>/dev/null
|
||||||
|
then
|
||||||
|
sed -E "s/^(domain|search)/#\1/g" -i /run/resolvconf/interface/*.dhclient
|
||||||
|
fi
|
||||||
|
|
||||||
|
grep -q '^supersede domain-name "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede domain-name "";' >> /etc/dhcp/dhclient.conf
|
||||||
|
grep -q '^supersede domain-search "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede domain-search "";' >> /etc/dhcp/dhclient.conf
|
||||||
|
grep -q '^supersede name "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede name "";' >> /etc/dhcp/dhclient.conf
|
||||||
|
systemctl restart resolvconf
|
||||||
|
fi
|
||||||
|
|
||||||
[[ -z "$regen_conf_files" ]] \
|
[[ -z "$regen_conf_files" ]] \
|
||||||
|| service dnsmasq restart
|
|| service dnsmasq restart
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,62 +11,66 @@ from yunohost.utils.packages import ynh_packages_version
|
||||||
class BaseSystemDiagnoser(Diagnoser):
|
class BaseSystemDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 3600 * 24
|
cache_duration = 600
|
||||||
dependencies = []
|
dependencies = []
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
# Detect virt technology (if not bare metal) and arch
|
# Detect virt technology (if not bare metal) and arch
|
||||||
# Also possibly the board name
|
# Gotta have this "|| true" because it systemd-detect-virt return 'none'
|
||||||
virt = check_output("systemd-detect-virt").strip() or "bare-metal"
|
# with an error code on bare metal ~.~
|
||||||
|
virt = check_output("systemd-detect-virt || true", shell=True).strip()
|
||||||
|
if virt.lower() == "none":
|
||||||
|
virt = "bare-metal"
|
||||||
|
|
||||||
|
# Detect arch
|
||||||
arch = check_output("dpkg --print-architecture").strip()
|
arch = check_output("dpkg --print-architecture").strip()
|
||||||
hardware = dict(meta={"test": "hardware"},
|
hardware = dict(meta={"test": "hardware"},
|
||||||
status="INFO",
|
status="INFO",
|
||||||
data={"virt": virt, "arch": arch},
|
data={"virt": virt, "arch": arch},
|
||||||
summary=("diagnosis_basesystem_hardware", {"virt": virt, "arch": arch}))
|
summary="diagnosis_basesystem_hardware")
|
||||||
|
|
||||||
|
# Also possibly the board name
|
||||||
if os.path.exists("/proc/device-tree/model"):
|
if os.path.exists("/proc/device-tree/model"):
|
||||||
model = read_file('/proc/device-tree/model').strip()
|
model = read_file('/proc/device-tree/model').strip()
|
||||||
hardware["data"]["board"] = model
|
hardware["data"]["model"] = model
|
||||||
hardware["details"] = [("diagnosis_basesystem_hardware_board", (model,))]
|
hardware["details"] = ["diagnosis_basesystem_hardware_board"]
|
||||||
|
|
||||||
yield hardware
|
yield hardware
|
||||||
|
|
||||||
# Kernel version
|
# Kernel version
|
||||||
kernel_version = read_file('/proc/sys/kernel/osrelease').strip()
|
kernel_version = read_file('/proc/sys/kernel/osrelease').strip()
|
||||||
yield dict(meta={"test": "kernel"},
|
yield dict(meta={"test": "kernel"},
|
||||||
|
data={"kernel_version": kernel_version},
|
||||||
status="INFO",
|
status="INFO",
|
||||||
summary=("diagnosis_basesystem_kernel", {"kernel_version": kernel_version}))
|
summary="diagnosis_basesystem_kernel")
|
||||||
|
|
||||||
# Debian release
|
# Debian release
|
||||||
debian_version = read_file("/etc/debian_version").strip()
|
debian_version = read_file("/etc/debian_version").strip()
|
||||||
yield dict(meta={"test": "host"},
|
yield dict(meta={"test": "host"},
|
||||||
|
data={"debian_version": debian_version},
|
||||||
status="INFO",
|
status="INFO",
|
||||||
summary=("diagnosis_basesystem_host", {"debian_version": debian_version}))
|
summary="diagnosis_basesystem_host")
|
||||||
|
|
||||||
# Yunohost packages versions
|
# Yunohost packages versions
|
||||||
ynh_packages = ynh_packages_version()
|
|
||||||
# We check if versions are consistent (e.g. all 3.6 and not 3 packages with 3.6 and the other with 3.5)
|
# We check if versions are consistent (e.g. all 3.6 and not 3 packages with 3.6 and the other with 3.5)
|
||||||
# This is a classical issue for upgrades that failed in the middle
|
# This is a classical issue for upgrades that failed in the middle
|
||||||
# (or people upgrading half of the package because they did 'apt upgrade' instead of 'dist-upgrade')
|
# (or people upgrading half of the package because they did 'apt upgrade' instead of 'dist-upgrade')
|
||||||
# Here, ynh_core_version is for example "3.5.4.12", so [:3] is "3.5" and we check it's the same for all packages
|
# Here, ynh_core_version is for example "3.5.4.12", so [:3] is "3.5" and we check it's the same for all packages
|
||||||
|
ynh_packages = ynh_packages_version()
|
||||||
ynh_core_version = ynh_packages["yunohost"]["version"]
|
ynh_core_version = ynh_packages["yunohost"]["version"]
|
||||||
consistent_versions = all(infos["version"][:3] == ynh_core_version[:3] for infos in ynh_packages.values())
|
consistent_versions = all(infos["version"][:3] == ynh_core_version[:3] for infos in ynh_packages.values())
|
||||||
ynh_version_details = [("diagnosis_basesystem_ynh_single_version", (package, infos["version"], infos["repo"]))
|
ynh_version_details = [("diagnosis_basesystem_ynh_single_version",
|
||||||
|
{"package":package,
|
||||||
|
"version": infos["version"],
|
||||||
|
"repo": infos["repo"]}
|
||||||
|
)
|
||||||
for package, infos in ynh_packages.items()]
|
for package, infos in ynh_packages.items()]
|
||||||
|
|
||||||
if consistent_versions:
|
|
||||||
yield dict(meta={"test": "ynh_versions"},
|
yield dict(meta={"test": "ynh_versions"},
|
||||||
data={"main_version": ynh_core_version, "repo": ynh_packages["yunohost"]["repo"]},
|
data={"main_version": ynh_core_version, "repo": ynh_packages["yunohost"]["repo"]},
|
||||||
status="INFO",
|
status="INFO" if consistent_versions else "ERROR",
|
||||||
summary=("diagnosis_basesystem_ynh_main_version",
|
summary="diagnosis_basesystem_ynh_main_version" if consistent_versions else "diagnosis_basesystem_ynh_inconsistent_versions",
|
||||||
{"main_version": ynh_core_version,
|
|
||||||
"repo": ynh_packages["yunohost"]["repo"]}),
|
|
||||||
details=ynh_version_details)
|
|
||||||
else:
|
|
||||||
yield dict(meta={"test": "ynh_versions"},
|
|
||||||
data={"main_version": ynh_core_version, "repo": ynh_packages["yunohost"]["repo"]},
|
|
||||||
status="ERROR",
|
|
||||||
summary=("diagnosis_basesystem_ynh_inconsistent_versions", {}),
|
|
||||||
details=ynh_version_details)
|
details=ynh_version_details)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,12 @@ from moulinette.utils.process import check_output
|
||||||
from moulinette.utils.filesystem import read_file
|
from moulinette.utils.filesystem import read_file
|
||||||
|
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
|
from yunohost.utils.network import get_network_interfaces
|
||||||
|
|
||||||
class IPDiagnoser(Diagnoser):
|
class IPDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 60
|
cache_duration = 600
|
||||||
dependencies = []
|
dependencies = []
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
@ -28,7 +28,7 @@ class IPDiagnoser(Diagnoser):
|
||||||
if not can_ping_ipv4 and not can_ping_ipv6:
|
if not can_ping_ipv4 and not can_ping_ipv6:
|
||||||
yield dict(meta={"test": "ping"},
|
yield dict(meta={"test": "ping"},
|
||||||
status="ERROR",
|
status="ERROR",
|
||||||
summary=("diagnosis_ip_not_connected_at_all", {}))
|
summary="diagnosis_ip_not_connected_at_all")
|
||||||
# Not much else we can do if there's no internet at all
|
# Not much else we can do if there's no internet at all
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ class IPDiagnoser(Diagnoser):
|
||||||
|
|
||||||
# In every case, we can check that resolvconf seems to be okay
|
# In every case, we can check that resolvconf seems to be okay
|
||||||
# (symlink managed by resolvconf service + pointing to dnsmasq)
|
# (symlink managed by resolvconf service + pointing to dnsmasq)
|
||||||
good_resolvconf = self.resolvconf_is_symlink() and self.resolvconf_points_to_localhost()
|
good_resolvconf = self.good_resolvconf()
|
||||||
|
|
||||||
# If we can't resolve domain names at all, that's a pretty big issue ...
|
# If we can't resolve domain names at all, that's a pretty big issue ...
|
||||||
# If it turns out that at the same time, resolvconf is bad, that's probably
|
# If it turns out that at the same time, resolvconf is bad, that's probably
|
||||||
|
@ -49,20 +49,19 @@ class IPDiagnoser(Diagnoser):
|
||||||
if not can_resolve_dns:
|
if not can_resolve_dns:
|
||||||
yield dict(meta={"test": "dnsresolv"},
|
yield dict(meta={"test": "dnsresolv"},
|
||||||
status="ERROR",
|
status="ERROR",
|
||||||
summary=("diagnosis_ip_broken_dnsresolution", {}) if good_resolvconf
|
summary="diagnosis_ip_broken_dnsresolution" if good_resolvconf else "diagnosis_ip_broken_resolvconf")
|
||||||
else ("diagnosis_ip_broken_resolvconf", {}))
|
|
||||||
return
|
return
|
||||||
# Otherwise, if the resolv conf is bad but we were able to resolve domain name,
|
# Otherwise, if the resolv conf is bad but we were able to resolve domain name,
|
||||||
# still warn that we're using a weird resolv conf ...
|
# still warn that we're using a weird resolv conf ...
|
||||||
elif not good_resolvconf:
|
elif not good_resolvconf:
|
||||||
yield dict(meta={"test": "dnsresolv"},
|
yield dict(meta={"test": "dnsresolv"},
|
||||||
status="WARNING",
|
status="WARNING",
|
||||||
summary=("diagnosis_ip_weird_resolvconf", {}),
|
summary="diagnosis_ip_weird_resolvconf",
|
||||||
details=[("diagnosis_ip_weird_resolvconf_details", ())])
|
details=["diagnosis_ip_weird_resolvconf_details"])
|
||||||
else:
|
else:
|
||||||
yield dict(meta={"test": "dnsresolv"},
|
yield dict(meta={"test": "dnsresolv"},
|
||||||
status="SUCCESS",
|
status="SUCCESS",
|
||||||
summary=("diagnosis_ip_dnsresolution_working", {}))
|
summary="diagnosis_ip_dnsresolution_working")
|
||||||
|
|
||||||
# ##################################################### #
|
# ##################################################### #
|
||||||
# IP DIAGNOSIS : Check that we're actually able to talk #
|
# IP DIAGNOSIS : Check that we're actually able to talk #
|
||||||
|
@ -72,17 +71,28 @@ class IPDiagnoser(Diagnoser):
|
||||||
ipv4 = self.get_public_ip(4) if can_ping_ipv4 else None
|
ipv4 = self.get_public_ip(4) if can_ping_ipv4 else None
|
||||||
ipv6 = self.get_public_ip(6) if can_ping_ipv6 else None
|
ipv6 = self.get_public_ip(6) if can_ping_ipv6 else None
|
||||||
|
|
||||||
yield dict(meta={"test": "ip", "version": 4},
|
network_interfaces = get_network_interfaces()
|
||||||
data=ipv4,
|
def get_local_ip(version):
|
||||||
status="SUCCESS" if ipv4 else "ERROR",
|
local_ip = {iface:addr[version].split("/")[0]
|
||||||
summary=("diagnosis_ip_connected_ipv4", {}) if ipv4
|
for iface, addr in network_interfaces.items() if version in addr}
|
||||||
else ("diagnosis_ip_no_ipv4", {}))
|
if not local_ip:
|
||||||
|
return None
|
||||||
|
elif len(local_ip):
|
||||||
|
return next(iter(local_ip.values()))
|
||||||
|
else:
|
||||||
|
return local_ip
|
||||||
|
|
||||||
yield dict(meta={"test": "ip", "version": 6},
|
yield dict(meta={"test": "ipv4"},
|
||||||
data=ipv6,
|
data={"global": ipv4, "local": get_local_ip("ipv4")},
|
||||||
|
status="SUCCESS" if ipv4 else "ERROR",
|
||||||
|
summary="diagnosis_ip_connected_ipv4" if ipv4 else "diagnosis_ip_no_ipv4",
|
||||||
|
details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv4 else None)
|
||||||
|
|
||||||
|
yield dict(meta={"test": "ipv6"},
|
||||||
|
data={"global": ipv6, "local": get_local_ip("ipv6")},
|
||||||
status="SUCCESS" if ipv6 else "WARNING",
|
status="SUCCESS" if ipv6 else "WARNING",
|
||||||
summary=("diagnosis_ip_connected_ipv6", {}) if ipv6
|
summary="diagnosis_ip_connected_ipv6" if ipv6 else "diagnosis_ip_no_ipv6",
|
||||||
else ("diagnosis_ip_no_ipv6", {}))
|
details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv6 else None)
|
||||||
|
|
||||||
# TODO / FIXME : add some attempt to detect ISP (using whois ?) ?
|
# TODO / FIXME : add some attempt to detect ISP (using whois ?) ?
|
||||||
|
|
||||||
|
@ -96,7 +106,7 @@ class IPDiagnoser(Diagnoser):
|
||||||
|
|
||||||
# If we are indeed connected in ipv4 or ipv6, we should find a default route
|
# If we are indeed connected in ipv4 or ipv6, we should find a default route
|
||||||
routes = check_output("ip -%s route" % protocol).split("\n")
|
routes = check_output("ip -%s route" % protocol).split("\n")
|
||||||
if not [r for r in routes if r.startswith("default")]:
|
if not any(r.startswith("default") for r in routes):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# We use the resolver file as a list of well-known, trustable (ie not google ;)) IPs that we can ping
|
# We use the resolver file as a list of well-known, trustable (ie not google ;)) IPs that we can ping
|
||||||
|
@ -121,13 +131,12 @@ class IPDiagnoser(Diagnoser):
|
||||||
def can_resolve_dns(self):
|
def can_resolve_dns(self):
|
||||||
return os.system("dig +short ip.yunohost.org >/dev/null 2>/dev/null") == 0
|
return os.system("dig +short ip.yunohost.org >/dev/null 2>/dev/null") == 0
|
||||||
|
|
||||||
def resolvconf_is_symlink(self):
|
def good_resolvconf(self):
|
||||||
return os.path.realpath("/etc/resolv.conf") == "/run/resolvconf/resolv.conf"
|
content = read_file("/etc/resolv.conf").strip().split("\n")
|
||||||
|
# Ignore comments and empty lines
|
||||||
def resolvconf_points_to_localhost(self):
|
content = [l.strip() for l in content if l.strip() and not l.strip().startswith("#") and not l.strip().startswith("search")]
|
||||||
file_ = "/etc/resolv.conf"
|
# We should only find a "nameserver 127.0.0.1"
|
||||||
resolvers = [r.split(" ")[1] for r in read_file(file_).split("\n") if r.startswith("nameserver")]
|
return len(content) == 1 and content[0].split() == ["nameserver", "127.0.0.1"]
|
||||||
return resolvers == ["127.0.0.1"]
|
|
||||||
|
|
||||||
def get_public_ip(self, protocol=4):
|
def get_public_ip(self, protocol=4):
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from moulinette.utils.process import check_output
|
|
||||||
from moulinette.utils.filesystem import read_file
|
from moulinette.utils.filesystem import read_file
|
||||||
|
|
||||||
|
from yunohost.utils.network import dig
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain
|
from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain
|
||||||
class DNSRecordsDiagnoser(Diagnoser):
|
class DNSRecordsDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 3600 * 24
|
cache_duration = 600
|
||||||
dependencies = ["ip"]
|
dependencies = ["ip"]
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
@ -38,11 +38,10 @@ class DNSRecordsDiagnoser(Diagnoser):
|
||||||
|
|
||||||
def check_domain(self, domain, is_main_domain, is_subdomain):
|
def check_domain(self, domain, is_main_domain, is_subdomain):
|
||||||
|
|
||||||
expected_configuration = _build_dns_conf(domain)
|
expected_configuration = _build_dns_conf(domain, include_empty_AAAA_if_no_ipv6=True)
|
||||||
|
|
||||||
# FIXME: Here if there are no AAAA record, we should add something to expect "no" AAAA record
|
|
||||||
# to properly diagnose situations where people have a AAAA record but no IPv6
|
|
||||||
categories = ["basic", "mail", "xmpp", "extra"]
|
categories = ["basic", "mail", "xmpp", "extra"]
|
||||||
|
# For subdomains, we only diagnosis A and AAAA records
|
||||||
if is_subdomain:
|
if is_subdomain:
|
||||||
categories = ["basic"]
|
categories = ["basic"]
|
||||||
|
|
||||||
|
@ -50,44 +49,92 @@ class DNSRecordsDiagnoser(Diagnoser):
|
||||||
|
|
||||||
records = expected_configuration[category]
|
records = expected_configuration[category]
|
||||||
discrepancies = []
|
discrepancies = []
|
||||||
|
results = {}
|
||||||
|
|
||||||
for r in records:
|
for r in records:
|
||||||
current_value = self.get_current_record(domain, r["name"], r["type"]) or "None"
|
id_ = r["type"] + ":" + r["name"]
|
||||||
expected_value = r["value"] if r["value"] != "@" else domain + "."
|
r["current"] = self.get_current_record(domain, r["name"], r["type"])
|
||||||
|
if r["value"] == "@":
|
||||||
|
r["value"] = domain + "."
|
||||||
|
|
||||||
if current_value == "None":
|
if self.current_record_match_expected(r):
|
||||||
discrepancies.append(("diagnosis_dns_missing_record", (r["type"], r["name"], expected_value)))
|
results[id_] = "OK"
|
||||||
elif current_value != expected_value:
|
else:
|
||||||
discrepancies.append(("diagnosis_dns_discrepancy", (r["type"], r["name"], expected_value, current_value)))
|
if r["current"] is None:
|
||||||
|
results[id_] = "MISSING"
|
||||||
|
discrepancies.append(("diagnosis_dns_missing_record", r))
|
||||||
|
else:
|
||||||
|
results[id_] = "WRONG"
|
||||||
|
discrepancies.append(("diagnosis_dns_discrepancy", r))
|
||||||
|
|
||||||
|
|
||||||
|
def its_important():
|
||||||
|
# Every mail DNS records are important for main domain
|
||||||
|
# For other domain, we only report it as a warning for now...
|
||||||
|
if is_main_domain and category == "mail":
|
||||||
|
return True
|
||||||
|
elif category == "basic":
|
||||||
|
# A bad or missing A record is critical ...
|
||||||
|
# And so is a wrong AAAA record
|
||||||
|
# (However, a missing AAAA record is acceptable)
|
||||||
|
if results["A:@"] != "OK" or results["AAAA:@"] == "WRONG":
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
if discrepancies:
|
if discrepancies:
|
||||||
status = "ERROR" if (category == "basic" or (is_main_domain and category != "extra")) else "WARNING"
|
status = "ERROR" if its_important() else "WARNING"
|
||||||
summary = ("diagnosis_dns_bad_conf", {"domain": domain, "category": category})
|
summary = "diagnosis_dns_bad_conf"
|
||||||
else:
|
else:
|
||||||
status = "SUCCESS"
|
status = "SUCCESS"
|
||||||
summary = ("diagnosis_dns_good_conf", {"domain": domain, "category": category})
|
summary = "diagnosis_dns_good_conf"
|
||||||
|
|
||||||
output = dict(meta={"domain": domain, "category": category},
|
output = dict(meta={"domain": domain, "category": category},
|
||||||
|
data=results,
|
||||||
status=status,
|
status=status,
|
||||||
summary=summary)
|
summary=summary)
|
||||||
|
|
||||||
if discrepancies:
|
if discrepancies:
|
||||||
output["details"] = discrepancies
|
output["details"] = ["diagnosis_dns_point_to_doc"] + discrepancies
|
||||||
|
|
||||||
yield output
|
yield output
|
||||||
|
|
||||||
def get_current_record(self, domain, name, type_):
|
def get_current_record(self, domain, name, type_):
|
||||||
if name == "@":
|
|
||||||
command = "dig +short @%s %s %s" % (self.resolver, type_, domain)
|
query = "%s.%s" % (name, domain) if name != "@" else domain
|
||||||
|
success, answers = dig(query, type_, resolvers="force_external")
|
||||||
|
|
||||||
|
if success != "ok":
|
||||||
|
return None
|
||||||
else:
|
else:
|
||||||
command = "dig +short @%s %s %s.%s" % (self.resolver, type_, name, domain)
|
return answers[0] if len(answers) == 1 else answers
|
||||||
# FIXME : gotta handle case where this command fails ...
|
|
||||||
# e.g. no internet connectivity (dependency mechanism to good result from 'ip' diagosis ?)
|
def current_record_match_expected(self, r):
|
||||||
# or the resolver is unavailable for some reason
|
if r["value"] is not None and r["current"] is None:
|
||||||
output = check_output(command).strip()
|
return False
|
||||||
if output.startswith('"') and output.endswith('"'):
|
if r["value"] is None and r["current"] is not None:
|
||||||
output = '"' + ' '.join(output.replace('"', ' ').split()) + '"'
|
return False
|
||||||
return output
|
elif isinstance(r["current"], list):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if r["type"] == "TXT":
|
||||||
|
# Split expected/current
|
||||||
|
# from "v=DKIM1; k=rsa; p=hugekey;"
|
||||||
|
# to a set like {'v=DKIM1', 'k=rsa', 'p=...'}
|
||||||
|
expected = set(r["value"].strip(';" ').replace(";", " ").split())
|
||||||
|
current = set(r["current"].strip(';" ').replace(";", " ").split())
|
||||||
|
|
||||||
|
# For SPF, ignore parts starting by ip4: or ip6:
|
||||||
|
if r["name"] == "@":
|
||||||
|
current = {part for part in current if not part.startswith("ip4:") and not part.startswith("ip6:")}
|
||||||
|
return expected == current
|
||||||
|
elif r["type"] == "MX":
|
||||||
|
# For MX, we want to ignore the priority
|
||||||
|
expected = r["value"].split()[-1]
|
||||||
|
current = r["current"].split()[-1]
|
||||||
|
return expected == current
|
||||||
|
else:
|
||||||
|
return r["current"] == r["value"]
|
||||||
|
|
||||||
|
|
||||||
def main(args, env, loggers):
|
def main(args, env, loggers):
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import requests
|
|
||||||
|
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError
|
||||||
|
@ -10,11 +9,13 @@ from yunohost.service import _get_services
|
||||||
class PortsDiagnoser(Diagnoser):
|
class PortsDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 3600
|
cache_duration = 600
|
||||||
dependencies = ["ip"]
|
dependencies = ["ip"]
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
|
# TODO: report a warning if port 53 or 5353 is exposed to the outside world...
|
||||||
|
|
||||||
# This dict is something like :
|
# This dict is something like :
|
||||||
# { 80: "nginx",
|
# { 80: "nginx",
|
||||||
# 25: "postfix",
|
# 25: "postfix",
|
||||||
|
@ -26,35 +27,89 @@ class PortsDiagnoser(Diagnoser):
|
||||||
for port in infos.get("needs_exposed_ports", []):
|
for port in infos.get("needs_exposed_ports", []):
|
||||||
ports[port] = service
|
ports[port] = service
|
||||||
|
|
||||||
|
ipversions = []
|
||||||
|
ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {}
|
||||||
|
if ipv4.get("status") == "SUCCESS":
|
||||||
|
ipversions.append(4)
|
||||||
|
|
||||||
|
# To be discussed: we could also make this check dependent on the
|
||||||
|
# existence of an AAAA record...
|
||||||
|
ipv6 = Diagnoser.get_cached_report("ip", item={"test": "ipv6"}) or {}
|
||||||
|
if ipv6.get("status") == "SUCCESS":
|
||||||
|
ipversions.append(6)
|
||||||
|
|
||||||
|
# Fetch test result for each relevant IP version
|
||||||
|
results = {}
|
||||||
|
for ipversion in ipversions:
|
||||||
try:
|
try:
|
||||||
r = requests.post('https://diagnosis.yunohost.org/check-ports', json={'ports': ports.keys()}, timeout=30)
|
r = Diagnoser.remote_diagnosis('check-ports',
|
||||||
if r.status_code not in [200, 400, 418]:
|
data={'ports': ports.keys()},
|
||||||
raise Exception("Bad response from the server https://diagnosis.yunohost.org/check-ports : %s - %s" % (str(r.status_code), r.content))
|
ipversion=ipversion)
|
||||||
r = r.json()
|
results[ipversion] = r["ports"]
|
||||||
if "status" not in r.keys():
|
|
||||||
raise Exception("Bad syntax for response ? Raw json: %s" % str(r))
|
|
||||||
elif r["status"] == "error":
|
|
||||||
if "content" in r.keys():
|
|
||||||
raise Exception(r["content"])
|
|
||||||
else:
|
|
||||||
raise Exception("Bad syntax for response ? Raw json: %s" % str(r))
|
|
||||||
elif r["status"] != "ok" or "ports" not in r.keys() or not isinstance(r["ports"], dict):
|
|
||||||
raise Exception("Bad syntax for response ? Raw json: %s" % str(r))
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise YunohostError("diagnosis_ports_could_not_diagnose", error=e)
|
yield dict(meta={"reason": "remote_diagnosis_failed", "ipversion": ipversion},
|
||||||
|
data={"error": str(e)},
|
||||||
|
status="WARNING",
|
||||||
|
summary="diagnosis_ports_could_not_diagnose",
|
||||||
|
details=["diagnosis_ports_could_not_diagnose_details"])
|
||||||
|
continue
|
||||||
|
|
||||||
|
ipversions = results.keys()
|
||||||
|
if not ipversions:
|
||||||
|
return
|
||||||
|
|
||||||
for port, service in sorted(ports.items()):
|
for port, service in sorted(ports.items()):
|
||||||
|
port = str(port)
|
||||||
category = services[service].get("category", "[?]")
|
category = services[service].get("category", "[?]")
|
||||||
if r["ports"].get(str(port), None) is not True:
|
|
||||||
yield dict(meta={"port": port, "needed_by": service},
|
# If both IPv4 and IPv6 (if applicable) are good
|
||||||
status="ERROR",
|
if all(results[ipversion].get(port) is True for ipversion in ipversions):
|
||||||
summary=("diagnosis_ports_unreachable", {"port": port}),
|
yield dict(meta={"port": port},
|
||||||
details=[("diagnosis_ports_needed_by", (service, category)), ("diagnosis_ports_forwarding_tip", ())])
|
data={"service": service, "category": category},
|
||||||
else:
|
|
||||||
yield dict(meta={"port": port, "needed_by": service},
|
|
||||||
status="SUCCESS",
|
status="SUCCESS",
|
||||||
summary=("diagnosis_ports_ok", {"port": port}),
|
summary="diagnosis_ports_ok",
|
||||||
details=[("diagnosis_ports_needed_by", (service, category))])
|
details=["diagnosis_ports_needed_by"])
|
||||||
|
# If both IPv4 and IPv6 (if applicable) are failed
|
||||||
|
elif all(results[ipversion].get(port) is not True for ipversion in ipversions):
|
||||||
|
yield dict(meta={"port": port},
|
||||||
|
data={"service": service, "category": category},
|
||||||
|
status="ERROR",
|
||||||
|
summary="diagnosis_ports_unreachable",
|
||||||
|
details=["diagnosis_ports_needed_by", "diagnosis_ports_forwarding_tip"])
|
||||||
|
# If only IPv4 is failed or only IPv6 is failed (if applicable)
|
||||||
|
else:
|
||||||
|
passed, failed = (4, 6) if results[4].get(port) is True else (6, 4)
|
||||||
|
|
||||||
|
# Failing in ipv4 is critical.
|
||||||
|
# If we failed in IPv6 but there's in fact no AAAA record
|
||||||
|
# It's an acceptable situation and we shall not report an
|
||||||
|
# error
|
||||||
|
# If any AAAA record is set, IPv6 is important...
|
||||||
|
def ipv6_is_important():
|
||||||
|
dnsrecords = Diagnoser.get_cached_report("dnsrecords") or {}
|
||||||
|
return any(record["data"]["AAAA:@"] in ["OK", "WRONG"] for record in dnsrecords.get("items", []))
|
||||||
|
|
||||||
|
if failed == 4 or ipv6_is_important():
|
||||||
|
yield dict(meta={"port": port},
|
||||||
|
data={"service": service, "category": category, "passed": passed, "failed": failed},
|
||||||
|
status="ERROR",
|
||||||
|
summary="diagnosis_ports_partially_unreachable",
|
||||||
|
details=["diagnosis_ports_needed_by", "diagnosis_ports_forwarding_tip"])
|
||||||
|
# So otherwise we report a success
|
||||||
|
# And in addition we report an info about the failure in IPv6
|
||||||
|
# *with a different meta* (important to avoid conflicts when
|
||||||
|
# fetching the other info...)
|
||||||
|
else:
|
||||||
|
yield dict(meta={"port": port},
|
||||||
|
data={"service": service, "category": category},
|
||||||
|
status="SUCCESS",
|
||||||
|
summary="diagnosis_ports_ok",
|
||||||
|
details=["diagnosis_ports_needed_by"])
|
||||||
|
yield dict(meta={"test": "ipv6", "port": port},
|
||||||
|
data={"service": service, "category": category, "passed": passed, "failed": failed},
|
||||||
|
status="INFO",
|
||||||
|
summary="diagnosis_ports_partially_unreachable",
|
||||||
|
details=["diagnosis_ports_needed_by", "diagnosis_ports_forwarding_tip"])
|
||||||
|
|
||||||
|
|
||||||
def main(args, env, loggers):
|
def main(args, env, loggers):
|
||||||
|
|
|
@ -4,58 +4,162 @@ import os
|
||||||
import random
|
import random
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
from moulinette.utils.filesystem import read_file
|
||||||
|
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
from yunohost.domain import domain_list
|
from yunohost.domain import domain_list
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError
|
||||||
|
|
||||||
|
DIAGNOSIS_SERVER = "diagnosis.yunohost.org"
|
||||||
|
|
||||||
|
|
||||||
class WebDiagnoser(Diagnoser):
|
class WebDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 3600
|
cache_duration = 600
|
||||||
dependencies = ["ip"]
|
dependencies = ["ip"]
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
nonce_digits = "0123456789abcedf"
|
|
||||||
|
|
||||||
all_domains = domain_list()["domains"]
|
all_domains = domain_list()["domains"]
|
||||||
|
domains_to_check = []
|
||||||
for domain in all_domains:
|
for domain in all_domains:
|
||||||
|
|
||||||
nonce = ''.join(random.choice(nonce_digits) for i in range(16))
|
# If the diagnosis location ain't defined, can't do diagnosis,
|
||||||
|
# probably because nginx conf manually modified...
|
||||||
|
nginx_conf = "/etc/nginx/conf.d/%s.conf" % domain
|
||||||
|
if ".well-known/ynh-diagnosis/" not in read_file(nginx_conf):
|
||||||
|
yield dict(meta={"domain": domain},
|
||||||
|
status="WARNING",
|
||||||
|
summary="diagnosis_http_nginx_conf_not_up_to_date",
|
||||||
|
details=["diagnosis_http_nginx_conf_not_up_to_date_details"])
|
||||||
|
else:
|
||||||
|
domains_to_check.append(domain)
|
||||||
|
|
||||||
|
self.nonce = ''.join(random.choice("0123456789abcedf") for i in range(16))
|
||||||
os.system("rm -rf /tmp/.well-known/ynh-diagnosis/")
|
os.system("rm -rf /tmp/.well-known/ynh-diagnosis/")
|
||||||
os.system("mkdir -p /tmp/.well-known/ynh-diagnosis/")
|
os.system("mkdir -p /tmp/.well-known/ynh-diagnosis/")
|
||||||
os.system("touch /tmp/.well-known/ynh-diagnosis/%s" % nonce)
|
os.system("touch /tmp/.well-known/ynh-diagnosis/%s" % self.nonce)
|
||||||
|
|
||||||
|
if not domains_to_check:
|
||||||
|
return
|
||||||
|
|
||||||
|
# To perform hairpinning test, we gotta make sure that port forwarding
|
||||||
|
# is working and therefore we'll do it only if at least one ipv4 domain
|
||||||
|
# works.
|
||||||
|
self.do_hairpinning_test = False
|
||||||
|
|
||||||
|
ipversions = []
|
||||||
|
ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {}
|
||||||
|
if ipv4.get("status") == "SUCCESS":
|
||||||
|
ipversions.append(4)
|
||||||
|
|
||||||
|
# To be discussed: we could also make this check dependent on the
|
||||||
|
# existence of an AAAA record...
|
||||||
|
ipv6 = Diagnoser.get_cached_report("ip", item={"test": "ipv6"}) or {}
|
||||||
|
if ipv6.get("status") == "SUCCESS":
|
||||||
|
ipversions.append(6)
|
||||||
|
|
||||||
|
for item in self.test_http(domains_to_check, ipversions):
|
||||||
|
yield item
|
||||||
|
|
||||||
|
# If at least one domain is correctly exposed to the outside,
|
||||||
|
# attempt to diagnose hairpinning situations. On network with
|
||||||
|
# hairpinning issues, the server may be correctly exposed on the
|
||||||
|
# outside, but from the outside, it will be as if the port forwarding
|
||||||
|
# was not configured... Hence, calling for example
|
||||||
|
# "curl --head the.global.ip" will simply timeout...
|
||||||
|
if self.do_hairpinning_test:
|
||||||
|
global_ipv4 = ipv4.get("data", {}).get("global", None)
|
||||||
|
if global_ipv4:
|
||||||
try:
|
try:
|
||||||
r = requests.post('https://diagnosis.yunohost.org/check-http', json={'domain': domain, "nonce": nonce}, timeout=30)
|
requests.head("http://" + global_ipv4, timeout=5)
|
||||||
if r.status_code not in [200, 400, 418]:
|
except requests.exceptions.Timeout:
|
||||||
raise Exception("Bad response from the server https://diagnosis.yunohost.org/check-http : %s - %s" % (str(r.status_code), r.content))
|
yield dict(meta={"test": "hairpinning"},
|
||||||
r = r.json()
|
status="WARNING",
|
||||||
if "status" not in r.keys():
|
summary="diagnosis_http_hairpinning_issue",
|
||||||
raise Exception("Bad syntax for response ? Raw json: %s" % str(r))
|
details=["diagnosis_http_hairpinning_issue_details"])
|
||||||
elif r["status"] == "error" and ("code" not in r.keys() or not r["code"].startswith("error_http_check_")):
|
except:
|
||||||
if "content" in r.keys():
|
# Well I dunno what to do if that's another exception
|
||||||
raise Exception(r["content"])
|
# type... That'll most probably *not* be an hairpinning
|
||||||
else:
|
# issue but something else super weird ...
|
||||||
raise Exception("Bad syntax for response ? Raw json: %s" % str(r))
|
pass
|
||||||
except Exception as e:
|
|
||||||
raise YunohostError("diagnosis_http_could_not_diagnose", error=e)
|
|
||||||
|
|
||||||
if r["status"] == "ok":
|
def test_http(self, domains, ipversions):
|
||||||
|
|
||||||
|
results = {}
|
||||||
|
for ipversion in ipversions:
|
||||||
|
try:
|
||||||
|
r = Diagnoser.remote_diagnosis('check-http',
|
||||||
|
data={'domains': domains,
|
||||||
|
"nonce": self.nonce},
|
||||||
|
ipversion=ipversion)
|
||||||
|
results[ipversion] = r["http"]
|
||||||
|
except Exception as e:
|
||||||
|
yield dict(meta={"reason": "remote_diagnosis_failed", "ipversion": ipversion},
|
||||||
|
data={"error": str(e)},
|
||||||
|
status="WARNING",
|
||||||
|
summary="diagnosis_http_could_not_diagnose",
|
||||||
|
details=["diagnosis_http_could_not_diagnose_details"])
|
||||||
|
continue
|
||||||
|
|
||||||
|
ipversions = results.keys()
|
||||||
|
if not ipversions:
|
||||||
|
return
|
||||||
|
|
||||||
|
for domain in domains:
|
||||||
|
|
||||||
|
# If both IPv4 and IPv6 (if applicable) are good
|
||||||
|
if all(results[ipversion][domain]["status"] == "ok" for ipversion in ipversions):
|
||||||
|
if 4 in ipversions:
|
||||||
|
self.do_hairpinning_test = True
|
||||||
yield dict(meta={"domain": domain},
|
yield dict(meta={"domain": domain},
|
||||||
status="SUCCESS",
|
status="SUCCESS",
|
||||||
summary=("diagnosis_http_ok", {"domain": domain}))
|
summary="diagnosis_http_ok")
|
||||||
else:
|
# If both IPv4 and IPv6 (if applicable) are failed
|
||||||
detail = r["code"].replace("error_http_check", "diagnosis_http") if "code" in r else "diagnosis_http_unknown_error"
|
elif all(results[ipversion][domain]["status"] != "ok" for ipversion in ipversions):
|
||||||
|
detail = results[4 if 4 in ipversions else 6][domain]["status"]
|
||||||
yield dict(meta={"domain": domain},
|
yield dict(meta={"domain": domain},
|
||||||
status="ERROR",
|
status="ERROR",
|
||||||
summary=("diagnosis_http_unreachable", {"domain": domain}),
|
summary="diagnosis_http_unreachable",
|
||||||
details=[(detail,())])
|
details=[detail.replace("error_http_check", "diagnosis_http")])
|
||||||
|
# If only IPv4 is failed or only IPv6 is failed (if applicable)
|
||||||
|
else:
|
||||||
|
passed, failed = (4, 6) if results[4][domain]["status"] == "ok" else (6, 4)
|
||||||
|
detail = results[failed][domain]["status"]
|
||||||
|
|
||||||
# In there or idk where else ...
|
# Failing in ipv4 is critical.
|
||||||
# try to diagnose hairpinning situation by crafting a request for the
|
# If we failed in IPv6 but there's in fact no AAAA record
|
||||||
# global ip (from within local network) and seeing if we're getting the right page ?
|
# It's an acceptable situation and we shall not report an
|
||||||
|
# error
|
||||||
|
def ipv6_is_important_for_this_domain():
|
||||||
|
dnsrecords = Diagnoser.get_cached_report("dnsrecords", item={"domain": domain, "category": "basic"}) or {}
|
||||||
|
AAAA_status = dnsrecords.get("data", {}).get("AAAA:@")
|
||||||
|
|
||||||
|
return AAAA_status in ["OK", "WRONG"]
|
||||||
|
|
||||||
|
if failed == 4 or ipv6_is_important_for_this_domain():
|
||||||
|
yield dict(meta={"domain": domain},
|
||||||
|
data={"passed": passed, "failed": failed},
|
||||||
|
status="ERROR",
|
||||||
|
summary="diagnosis_http_partially_unreachable",
|
||||||
|
details=[detail.replace("error_http_check", "diagnosis_http")])
|
||||||
|
# So otherwise we report a success (note that this info is
|
||||||
|
# later used to know that ACME challenge is doable)
|
||||||
|
#
|
||||||
|
# And in addition we report an info about the failure in IPv6
|
||||||
|
# *with a different meta* (important to avoid conflicts when
|
||||||
|
# fetching the other info...)
|
||||||
|
else:
|
||||||
|
self.do_hairpinning_test = True
|
||||||
|
yield dict(meta={"domain": domain},
|
||||||
|
status="SUCCESS",
|
||||||
|
summary="diagnosis_http_ok")
|
||||||
|
yield dict(meta={"test": "ipv6", "domain": domain},
|
||||||
|
data={"passed": passed, "failed": failed},
|
||||||
|
status="INFO",
|
||||||
|
summary="diagnosis_http_partially_unreachable",
|
||||||
|
details=[detail.replace("error_http_check", "diagnosis_http")])
|
||||||
|
|
||||||
|
|
||||||
def main(args, env, loggers):
|
def main(args, env, loggers):
|
||||||
|
|
|
@ -1,42 +1,238 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import dns.resolver
|
||||||
|
import socket
|
||||||
|
import re
|
||||||
|
|
||||||
|
from subprocess import CalledProcessError
|
||||||
|
|
||||||
|
from moulinette.utils.process import check_output
|
||||||
|
from moulinette.utils.filesystem import read_yaml
|
||||||
|
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
|
from yunohost.domain import _get_maindomain, domain_list
|
||||||
|
from yunohost.settings import settings_get
|
||||||
|
from yunohost.utils.network import dig
|
||||||
|
|
||||||
|
DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/other/dnsbl_list.yml"
|
||||||
|
|
||||||
|
|
||||||
class MailDiagnoser(Diagnoser):
|
class MailDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 3600
|
cache_duration = 600
|
||||||
dependencies = ["ip"]
|
dependencies = ["ip"]
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
# Is outgoing port 25 filtered somehow ?
|
self.ehlo_domain = _get_maindomain()
|
||||||
if os.system('/bin/nc -z -w2 yunohost.org 25') == 0:
|
self.mail_domains = domain_list()["domains"]
|
||||||
yield dict(meta={"test": "ougoing_port_25"},
|
self.ipversions, self.ips = self.get_ips_checked()
|
||||||
|
|
||||||
|
# TODO Is a A/AAAA and MX Record ?
|
||||||
|
# TODO Are outgoing public IPs authorized to send mail by SPF ?
|
||||||
|
# TODO Validate DKIM and dmarc ?
|
||||||
|
# TODO check that the recent mail logs are not filled with thousand of email sending (unusual number of mail sent)
|
||||||
|
# TODO check for unusual failed sending attempt being refused in the logs ?
|
||||||
|
checks = ["check_outgoing_port_25", "check_ehlo", "check_fcrdns",
|
||||||
|
"check_blacklist", "check_queue"]
|
||||||
|
for check in checks:
|
||||||
|
self.logger_debug("Running " + check)
|
||||||
|
reports = list(getattr(self, check)())
|
||||||
|
for report in reports:
|
||||||
|
yield report
|
||||||
|
if not reports:
|
||||||
|
name = check[6:]
|
||||||
|
yield dict(meta={"test": "mail_" + name},
|
||||||
status="SUCCESS",
|
status="SUCCESS",
|
||||||
summary=("diagnosis_mail_ougoing_port_25_ok",{}))
|
summary="diagnosis_mail_" + name + "_ok")
|
||||||
else:
|
|
||||||
yield dict(meta={"test": "outgoing_port_25"},
|
|
||||||
|
def check_outgoing_port_25(self):
|
||||||
|
"""
|
||||||
|
Check outgoing port 25 is open and not blocked by router
|
||||||
|
This check is ran on IPs we could used to send mail.
|
||||||
|
"""
|
||||||
|
|
||||||
|
for ipversion in self.ipversions:
|
||||||
|
cmd = '/bin/nc -{ipversion} -z -w2 yunohost.org 25'.format(ipversion=ipversion)
|
||||||
|
if os.system(cmd) != 0:
|
||||||
|
yield dict(meta={"test": "outgoing_port_25", "ipversion": ipversion},
|
||||||
|
data={},
|
||||||
status="ERROR",
|
status="ERROR",
|
||||||
summary=("diagnosis_mail_ougoing_port_25_blocked",{}))
|
summary="diagnosis_mail_outgoing_port_25_blocked",
|
||||||
|
details=["diagnosis_mail_outgoing_port_25_blocked_details",
|
||||||
|
"diagnosis_mail_outgoing_port_25_blocked_relay_vpn"])
|
||||||
|
|
||||||
|
|
||||||
|
def check_ehlo(self):
|
||||||
|
"""
|
||||||
|
Check the server is reachable from outside and it's the good one
|
||||||
|
This check is ran on IPs we could used to send mail.
|
||||||
|
"""
|
||||||
|
|
||||||
# Mail blacklist using dig requests (c.f. ljf's code)
|
for ipversion in self.ipversions:
|
||||||
|
try:
|
||||||
|
r = Diagnoser.remote_diagnosis('check-smtp',
|
||||||
|
data={},
|
||||||
|
ipversion=ipversion)
|
||||||
|
except Exception as e:
|
||||||
|
yield dict(meta={"test": "mail_ehlo", "reason": "remote_server_failed",
|
||||||
|
"ipversion": ipversion},
|
||||||
|
data={"error": str(e)},
|
||||||
|
status="WARNING",
|
||||||
|
summary="diagnosis_mail_ehlo_could_not_diagnose",
|
||||||
|
details=["diagnosis_mail_ehlo_could_not_diagnose_details"])
|
||||||
|
continue
|
||||||
|
|
||||||
# SMTP reachability (c.f. check-smtp to be implemented on yunohost's remote diagnoser)
|
if r["status"] != "ok":
|
||||||
|
summary = r["status"].replace("error_smtp_", "diagnosis_mail_ehlo_")
|
||||||
|
yield dict(meta={"test": "mail_ehlo", "ipversion": ipversion},
|
||||||
|
data={},
|
||||||
|
status="ERROR",
|
||||||
|
summary=summary,
|
||||||
|
details=[summary + "_details"])
|
||||||
|
elif r["helo"] != self.ehlo_domain:
|
||||||
|
yield dict(meta={"test": "mail_ehlo", "ipversion": ipversion},
|
||||||
|
data={"wrong_ehlo": r["helo"], "right_ehlo": self.ehlo_domain},
|
||||||
|
status="ERROR",
|
||||||
|
summary="diagnosis_mail_ehlo_wrong",
|
||||||
|
details=["diagnosis_mail_ehlo_wrong_details"])
|
||||||
|
|
||||||
# ideally, SPF / DMARC / DKIM validation ... (c.f. https://github.com/alexAubin/yunoScripts/blob/master/yunoDKIM.py possibly though that looks horrible)
|
|
||||||
|
|
||||||
# check that the mail queue is not filled with hundreds of email pending
|
def check_fcrdns(self):
|
||||||
|
"""
|
||||||
|
Check the reverse DNS is well defined by doing a Forward-confirmed
|
||||||
|
reverse DNS check
|
||||||
|
This check is ran on IPs we could used to send mail.
|
||||||
|
"""
|
||||||
|
|
||||||
# check that the recent mail logs are not filled with thousand of email sending (unusual number of mail sent)
|
for ip in self.ips:
|
||||||
|
if ":" in ip:
|
||||||
|
ipversion = 6
|
||||||
|
details = ["diagnosis_mail_fcrdns_nok_details",
|
||||||
|
"diagnosis_mail_fcrdns_nok_alternatives_6"]
|
||||||
|
else:
|
||||||
|
ipversion = 4
|
||||||
|
details = ["diagnosis_mail_fcrdns_nok_details",
|
||||||
|
"diagnosis_mail_fcrdns_nok_alternatives_4"]
|
||||||
|
|
||||||
# check for unusual failed sending attempt being refused in the logs ?
|
try:
|
||||||
|
rdns_domain, _, _ = socket.gethostbyaddr(ip)
|
||||||
|
except socket.herror:
|
||||||
|
yield dict(meta={"test": "mail_fcrdns", "ipversion": ipversion},
|
||||||
|
data={"ip": ip, "ehlo_domain": self.ehlo_domain},
|
||||||
|
status="ERROR",
|
||||||
|
summary="diagnosis_mail_fcrdns_dns_missing",
|
||||||
|
details=details)
|
||||||
|
continue
|
||||||
|
if rdns_domain != self.ehlo_domain:
|
||||||
|
details = ["diagnosis_mail_fcrdns_different_from_ehlo_domain_details"] + details
|
||||||
|
yield dict(meta={"test": "mail_fcrdns", "ipversion": ipversion},
|
||||||
|
data={"ip": ip,
|
||||||
|
"ehlo_domain": self.ehlo_domain,
|
||||||
|
"rdns_domain": rdns_domain},
|
||||||
|
status="ERROR",
|
||||||
|
summary="diagnosis_mail_fcrdns_different_from_ehlo_domain",
|
||||||
|
details=details)
|
||||||
|
|
||||||
|
|
||||||
|
def check_blacklist(self):
|
||||||
|
"""
|
||||||
|
Check with dig onto blacklist DNS server
|
||||||
|
This check is ran on IPs and domains we could used to send mail.
|
||||||
|
"""
|
||||||
|
|
||||||
|
dns_blacklists = read_yaml(DEFAULT_DNS_BLACKLIST)
|
||||||
|
for item in self.ips + self.mail_domains:
|
||||||
|
for blacklist in dns_blacklists:
|
||||||
|
item_type = "domain"
|
||||||
|
if ":" in item:
|
||||||
|
item_type = 'ipv6'
|
||||||
|
elif re.match(r'^\d+\.\d+\.\d+\.\d+$', item):
|
||||||
|
item_type = 'ipv4'
|
||||||
|
|
||||||
|
if not blacklist[item_type]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Build the query for DNSBL
|
||||||
|
subdomain = item
|
||||||
|
if item_type != "domain":
|
||||||
|
rev = dns.reversename.from_address(item)
|
||||||
|
subdomain = str(rev.split(3)[0])
|
||||||
|
query = subdomain + '.' + blacklist['dns_server']
|
||||||
|
|
||||||
|
# Do the DNS Query
|
||||||
|
status, _ = dig(query, 'A')
|
||||||
|
if status != 'ok':
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Try to get the reason
|
||||||
|
details = []
|
||||||
|
status, answers = dig(query, 'TXT')
|
||||||
|
reason = "-"
|
||||||
|
if status == 'ok':
|
||||||
|
reason = ', '.join(answers)
|
||||||
|
details.append("diagnosis_mail_blacklist_reason")
|
||||||
|
|
||||||
|
details.append("diagnosis_mail_blacklist_website")
|
||||||
|
|
||||||
|
yield dict(meta={"test": "mail_blacklist", "item": item,
|
||||||
|
"blacklist": blacklist["dns_server"]},
|
||||||
|
data={'blacklist_name': blacklist['name'],
|
||||||
|
'blacklist_website': blacklist['website'],
|
||||||
|
'reason': reason},
|
||||||
|
status="ERROR",
|
||||||
|
summary='diagnosis_mail_blacklist_listed_by',
|
||||||
|
details=details)
|
||||||
|
|
||||||
|
def check_queue(self):
|
||||||
|
"""
|
||||||
|
Check mail queue is not filled with hundreds of email pending
|
||||||
|
"""
|
||||||
|
|
||||||
|
command = 'postqueue -p | grep -v "Mail queue is empty" | grep -c "^[A-Z0-9]" || true'
|
||||||
|
try:
|
||||||
|
output = check_output(command).strip()
|
||||||
|
pending_emails = int(output)
|
||||||
|
except (ValueError, CalledProcessError) as e:
|
||||||
|
yield dict(meta={"test": "mail_queue"},
|
||||||
|
data={"error": str(e)},
|
||||||
|
status="ERROR",
|
||||||
|
summary="diagnosis_mail_queue_unavailable",
|
||||||
|
details="diagnosis_mail_queue_unavailable_details")
|
||||||
|
else:
|
||||||
|
if pending_emails > 100:
|
||||||
|
yield dict(meta={"test": "mail_queue"},
|
||||||
|
data={'nb_pending': pending_emails},
|
||||||
|
status="WARNING",
|
||||||
|
summary="diagnosis_mail_queue_too_big")
|
||||||
|
else:
|
||||||
|
yield dict(meta={"test": "mail_queue"},
|
||||||
|
data={'nb_pending': pending_emails},
|
||||||
|
status="SUCCESS",
|
||||||
|
summary="diagnosis_mail_queue_ok")
|
||||||
|
|
||||||
|
|
||||||
|
def get_ips_checked(self):
|
||||||
|
outgoing_ipversions = []
|
||||||
|
outgoing_ips = []
|
||||||
|
ipv4 = Diagnoser.get_cached_report("ip", {"test": "ipv4"}) or {}
|
||||||
|
if ipv4.get("status") == "SUCCESS":
|
||||||
|
outgoing_ipversions.append(4)
|
||||||
|
global_ipv4 = ipv4.get("data", {}).get("global", {})
|
||||||
|
if global_ipv4:
|
||||||
|
outgoing_ips.append(global_ipv4)
|
||||||
|
|
||||||
|
if settings_get("smtp.allow_ipv6"):
|
||||||
|
ipv6 = Diagnoser.get_cached_report("ip", {"test": "ipv6"}) or {}
|
||||||
|
if ipv6.get("status") == "SUCCESS":
|
||||||
|
outgoing_ipversions.append(6)
|
||||||
|
global_ipv6 = ipv6.get("data", {}).get("global", {})
|
||||||
|
if global_ipv6:
|
||||||
|
outgoing_ips.append(global_ipv6)
|
||||||
|
return (outgoing_ipversions, outgoing_ips)
|
||||||
|
|
||||||
def main(args, env, loggers):
|
def main(args, env, loggers):
|
||||||
return MailDiagnoser(args, env, loggers).diagnose()
|
return MailDiagnoser(args, env, loggers).diagnose()
|
||||||
|
|
|
@ -17,21 +17,22 @@ class ServicesDiagnoser(Diagnoser):
|
||||||
|
|
||||||
for service, result in sorted(all_result.items()):
|
for service, result in sorted(all_result.items()):
|
||||||
|
|
||||||
item = dict(meta={"service": service})
|
item = dict(meta={"service": service},
|
||||||
|
data={"status": result["status"], "configuration": result["configuration"]})
|
||||||
|
|
||||||
if result["status"] != "running":
|
if result["status"] != "running":
|
||||||
item["status"] = "ERROR"
|
item["status"] = "ERROR"
|
||||||
item["summary"] = ("diagnosis_services_bad_status", {"service": service, "status": result["status"]})
|
item["summary"] = "diagnosis_services_bad_status"
|
||||||
item["details"] = [("diagnosis_services_bad_status_tip", (service,))]
|
item["details"] = ["diagnosis_services_bad_status_tip"]
|
||||||
|
|
||||||
elif result["configuration"] == "broken":
|
elif result["configuration"] == "broken":
|
||||||
item["status"] = "WARNING"
|
item["status"] = "WARNING"
|
||||||
item["summary"] = ("diagnosis_services_conf_broken", {"service": service})
|
item["summary"] = "diagnosis_services_conf_broken"
|
||||||
item["details"] = [(d, tuple()) for d in result["configuration-details"]]
|
item["details"] = result["configuration-details"]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
item["status"] = "SUCCESS"
|
item["status"] = "SUCCESS"
|
||||||
item["summary"] = ("diagnosis_services_running", {"service": service, "status": result["status"]})
|
item["summary"] = "diagnosis_services_running"
|
||||||
|
|
||||||
yield item
|
yield item
|
||||||
|
|
||||||
|
|
|
@ -7,30 +7,34 @@ from yunohost.diagnosis import Diagnoser
|
||||||
class SystemResourcesDiagnoser(Diagnoser):
|
class SystemResourcesDiagnoser(Diagnoser):
|
||||||
|
|
||||||
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
|
||||||
cache_duration = 3600 * 24
|
cache_duration = 300
|
||||||
dependencies = []
|
dependencies = []
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
|
MB = 1024**2
|
||||||
|
GB = MB*1024
|
||||||
|
|
||||||
#
|
#
|
||||||
# RAM
|
# RAM
|
||||||
#
|
#
|
||||||
|
|
||||||
ram = psutil.virtual_memory()
|
ram = psutil.virtual_memory()
|
||||||
ram_total_abs_MB = ram.total / (1024**2)
|
ram_available_percent = 100 * ram.available / ram.total
|
||||||
ram_available_abs_MB = ram.available / (1024**2)
|
item = dict(meta={"test": "ram"},
|
||||||
ram_available_percent = round(100 * ram.available / ram.total)
|
data={"total": human_size(ram.total),
|
||||||
item = dict(meta={"test": "ram"})
|
"available": human_size(ram.available),
|
||||||
infos = {"total_abs_MB": ram_total_abs_MB, "available_abs_MB": ram_available_abs_MB, "available_percent": ram_available_percent}
|
"available_percent": round_(ram_available_percent)})
|
||||||
if ram_available_abs_MB < 100 or ram_available_percent < 5:
|
|
||||||
|
if ram.available < 100 * MB or ram_available_percent < 5:
|
||||||
item["status"] = "ERROR"
|
item["status"] = "ERROR"
|
||||||
item["summary"] = ("diagnosis_ram_verylow", infos)
|
item["summary"] = "diagnosis_ram_verylow"
|
||||||
elif ram_available_abs_MB < 200 or ram_available_percent < 10:
|
elif ram.available < 200 * MB or ram_available_percent < 10:
|
||||||
item["status"] = "WARNING"
|
item["status"] = "WARNING"
|
||||||
item["summary"] = ("diagnosis_ram_low", infos)
|
item["summary"] = "diagnosis_ram_low"
|
||||||
else:
|
else:
|
||||||
item["status"] = "SUCCESS"
|
item["status"] = "SUCCESS"
|
||||||
item["summary"] = ("diagnosis_ram_ok", infos)
|
item["summary"] = "diagnosis_ram_ok"
|
||||||
yield item
|
yield item
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -38,20 +42,21 @@ class SystemResourcesDiagnoser(Diagnoser):
|
||||||
#
|
#
|
||||||
|
|
||||||
swap = psutil.swap_memory()
|
swap = psutil.swap_memory()
|
||||||
swap_total_abs_MB = swap.total / (1024*1024)
|
item = dict(meta={"test": "swap"},
|
||||||
item = dict(meta={"test": "swap"})
|
data={"total": human_size(swap.total), "recommended": "512 MiB"})
|
||||||
infos = {"total_MB": swap_total_abs_MB}
|
if swap.total <= 1 * MB:
|
||||||
if swap_total_abs_MB <= 0:
|
|
||||||
item["status"] = "ERROR"
|
item["status"] = "ERROR"
|
||||||
item["summary"] = ("diagnosis_swap_none", infos)
|
item["summary"] = "diagnosis_swap_none"
|
||||||
elif swap_total_abs_MB <= 256:
|
elif swap.total <= 512 * MB:
|
||||||
item["status"] = "WARNING"
|
item["status"] = "WARNING"
|
||||||
item["summary"] = ("diagnosis_swap_notsomuch", infos)
|
item["summary"] = "diagnosis_swap_notsomuch"
|
||||||
else:
|
else:
|
||||||
item["status"] = "SUCCESS"
|
item["status"] = "SUCCESS"
|
||||||
item["summary"] = ("diagnosis_swap_ok", infos)
|
item["summary"] = "diagnosis_swap_ok"
|
||||||
yield item
|
yield item
|
||||||
|
|
||||||
|
# FIXME : add a check that swapiness is low if swap is on a sdcard...
|
||||||
|
|
||||||
#
|
#
|
||||||
# Disks usage
|
# Disks usage
|
||||||
#
|
#
|
||||||
|
@ -63,23 +68,54 @@ class SystemResourcesDiagnoser(Diagnoser):
|
||||||
mountpoint = disk_partition.mountpoint
|
mountpoint = disk_partition.mountpoint
|
||||||
|
|
||||||
usage = psutil.disk_usage(mountpoint)
|
usage = psutil.disk_usage(mountpoint)
|
||||||
free_abs_GB = usage.free / (1024 ** 3)
|
free_percent = round_(100 - usage.percent)
|
||||||
free_percent = 100 - usage.percent
|
|
||||||
|
|
||||||
item = dict(meta={"test": "diskusage", "mountpoint": mountpoint})
|
item = dict(meta={"test": "diskusage", "mountpoint": mountpoint},
|
||||||
infos = {"mountpoint": mountpoint, "device": device, "free_abs_GB": free_abs_GB, "free_percent": free_percent}
|
data={"device": device, "total": human_size(usage.total), "free": human_size(usage.free), "free_percent": free_percent})
|
||||||
if free_abs_GB < 1 or free_percent < 5:
|
|
||||||
|
# Special checks for /boot partition because they sometimes are
|
||||||
|
# pretty small and that's kind of okay... (for example on RPi)
|
||||||
|
if mountpoint.startswith("/boot"):
|
||||||
|
if usage.free < 10 * MB or free_percent < 10:
|
||||||
item["status"] = "ERROR"
|
item["status"] = "ERROR"
|
||||||
item["summary"] = ("diagnosis_diskusage_verylow", infos)
|
item["summary"] = "diagnosis_diskusage_verylow"
|
||||||
elif free_abs_GB < 2 or free_percent < 10:
|
elif usage.free < 20 * MB or free_percent < 20:
|
||||||
item["status"] = "WARNING"
|
item["status"] = "WARNING"
|
||||||
item["summary"] = ("diagnosis_diskusage_low", infos)
|
item["summary"] = "diagnosis_diskusage_low"
|
||||||
else:
|
else:
|
||||||
item["status"] = "SUCCESS"
|
item["status"] = "SUCCESS"
|
||||||
item["summary"] = ("diagnosis_diskusage_ok", infos)
|
item["summary"] = "diagnosis_diskusage_ok"
|
||||||
|
else:
|
||||||
|
if usage.free < 1 * GB or free_percent < 5:
|
||||||
|
item["status"] = "ERROR"
|
||||||
|
item["summary"] = "diagnosis_diskusage_verylow"
|
||||||
|
elif usage.free < 2 * GB or free_percent < 10:
|
||||||
|
item["status"] = "WARNING"
|
||||||
|
item["summary"] = "diagnosis_diskusage_low"
|
||||||
|
else:
|
||||||
|
item["status"] = "SUCCESS"
|
||||||
|
item["summary"] = "diagnosis_diskusage_ok"
|
||||||
|
|
||||||
|
|
||||||
yield item
|
yield item
|
||||||
|
|
||||||
|
|
||||||
|
def human_size(bytes_):
|
||||||
|
# Adapted from https://stackoverflow.com/a/1094933
|
||||||
|
for unit in ['','ki','Mi','Gi','Ti','Pi','Ei','Zi']:
|
||||||
|
if abs(bytes_) < 1024.0:
|
||||||
|
return "%s %sB" % (round_(bytes_), unit)
|
||||||
|
bytes_ /= 1024.0
|
||||||
|
return "%s %sB" % (round_(bytes_), 'Yi')
|
||||||
|
|
||||||
|
|
||||||
|
def round_(n):
|
||||||
|
# round_(22.124) -> 22
|
||||||
|
# round_(9.45) -> 9.4
|
||||||
|
n = round(n, 1)
|
||||||
|
if n > 10:
|
||||||
|
n = int(round(n))
|
||||||
|
return n
|
||||||
|
|
||||||
def main(args, env, loggers):
|
def main(args, env, loggers):
|
||||||
return SystemResourcesDiagnoser(args, env, loggers).diagnose()
|
return SystemResourcesDiagnoser(args, env, loggers).diagnose()
|
||||||
|
|
|
@ -4,8 +4,7 @@ import os
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
from yunohost.regenconf import manually_modified_files
|
from yunohost.regenconf import _get_regenconf_infos, _calculate_hash
|
||||||
#from yunohost.regenconf import manually_modified_files, manually_modified_files_compared_to_debian_default
|
|
||||||
|
|
||||||
|
|
||||||
class RegenconfDiagnoser(Diagnoser):
|
class RegenconfDiagnoser(Diagnoser):
|
||||||
|
@ -16,28 +15,27 @@ class RegenconfDiagnoser(Diagnoser):
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
regenconf_modified_files = manually_modified_files()
|
regenconf_modified_files = list(self.manually_modified_files())
|
||||||
#debian_modified_files = manually_modified_files_compared_to_debian_default(ignore_handled_by_regenconf=True)
|
|
||||||
|
|
||||||
if regenconf_modified_files == []:
|
if not regenconf_modified_files:
|
||||||
yield dict(meta={"test": "regenconf"},
|
yield dict(meta={"test": "regenconf"},
|
||||||
status="SUCCESS",
|
status="SUCCESS",
|
||||||
summary=("diagnosis_regenconf_allgood", {})
|
summary="diagnosis_regenconf_allgood"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
for f in regenconf_modified_files:
|
for f in regenconf_modified_files:
|
||||||
yield dict(meta={"test": "regenconf", "file": f},
|
yield dict(meta={"test": "regenconf", "category": f['category'], "file": f['path']},
|
||||||
status="WARNING",
|
status="WARNING",
|
||||||
summary=("diagnosis_regenconf_manually_modified", {"file": f}),
|
summary="diagnosis_regenconf_manually_modified",
|
||||||
details=[("diagnosis_regenconf_manually_modified_details", {})]
|
details=["diagnosis_regenconf_manually_modified_details"]
|
||||||
)
|
)
|
||||||
|
|
||||||
#for f in debian_modified_files:
|
def manually_modified_files(self):
|
||||||
# yield dict(meta={"test": "debian", "file": f},
|
|
||||||
# status="WARNING",
|
for category, infos in _get_regenconf_infos().items():
|
||||||
# summary=("diagnosis_regenconf_manually_modified_debian", {"file": f}),
|
for path, hash_ in infos["conffiles"].items():
|
||||||
# details=[("diagnosis_regenconf_manually_modified_debian_details", {})]
|
if hash_ != _calculate_hash(path):
|
||||||
# )
|
yield {"path": path, "category": category}
|
||||||
|
|
||||||
|
|
||||||
def main(args, env, loggers):
|
def main(args, env, loggers):
|
||||||
|
|
|
@ -21,13 +21,13 @@ class SecurityDiagnoser(Diagnoser):
|
||||||
if self.is_vulnerable_to_meltdown():
|
if self.is_vulnerable_to_meltdown():
|
||||||
yield dict(meta={"test": "meltdown"},
|
yield dict(meta={"test": "meltdown"},
|
||||||
status="ERROR",
|
status="ERROR",
|
||||||
summary=("diagnosis_security_vulnerable_to_meltdown", {}),
|
summary="diagnosis_security_vulnerable_to_meltdown",
|
||||||
details=[("diagnosis_security_vulnerable_to_meltdown_details", ())]
|
details=["diagnosis_security_vulnerable_to_meltdown_details"]
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
yield dict(meta={},
|
yield dict(meta={},
|
||||||
status="SUCCESS",
|
status="SUCCESS",
|
||||||
summary=("diagnosis_security_all_good", {})
|
summary="diagnosis_security_all_good"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
184
data/other/dnsbl_list.yml
Normal file
184
data/other/dnsbl_list.yml
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
# Used by GAFAM
|
||||||
|
- name: Spamhaus ZEN
|
||||||
|
dns_server: zen.spamhaus.org
|
||||||
|
website: https://www.spamhaus.org/zen/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: true
|
||||||
|
domain: false
|
||||||
|
- name: Barracuda Reputation Block List
|
||||||
|
dns_server: b.barracudacentral.org
|
||||||
|
website: https://barracudacentral.org/rbl/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: Hostkarma
|
||||||
|
dns_server: hostkarma.junkemailfilter.com
|
||||||
|
website: https://ipadmin.junkemailfilter.com/remove.php
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: ImproWare IP based spamlist
|
||||||
|
dns_server: spamrbl.imp.ch
|
||||||
|
website: https://antispam.imp.ch/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: ImproWare IP based wormlist
|
||||||
|
dns_server: wormrbl.imp.ch
|
||||||
|
website: https://antispam.imp.ch/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: Backscatterer.org
|
||||||
|
dns_server: ips.backscatterer.org
|
||||||
|
website: http://www.backscatterer.org/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: inps.de
|
||||||
|
dns_server: dnsbl.inps.de
|
||||||
|
website: http://dnsbl.inps.de/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: LASHBACK
|
||||||
|
dns_server: ubl.unsubscore.com
|
||||||
|
website: https://blacklist.lashback.com/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: Mailspike.org
|
||||||
|
dns_server: bl.mailspike.net
|
||||||
|
website: http://www.mailspike.net/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: NiX Spam
|
||||||
|
dns_server: ix.dnsbl.manitu.net
|
||||||
|
website: http://www.dnsbl.manitu.net/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: REDHAWK
|
||||||
|
dns_server: access.redhawk.org
|
||||||
|
website: https://www.redhawk.org/SpamHawk/query.php
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: SORBS Open SMTP relays
|
||||||
|
dns_server: smtp.dnsbl.sorbs.net
|
||||||
|
website: http://www.sorbs.net/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: SORBS Spamhost (last 28 days)
|
||||||
|
dns_server: recent.spam.dnsbl.sorbs.net
|
||||||
|
website: http://www.sorbs.net/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: SORBS Spamhost (last 48 hours)
|
||||||
|
dns_server: new.spam.dnsbl.sorbs.net
|
||||||
|
website: http://www.sorbs.net/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: SpamCop Blocking List
|
||||||
|
dns_server: bl.spamcop.net
|
||||||
|
website: https://www.spamcop.net/bl.shtml
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: Spam Eating Monkey SEM-BACKSCATTER
|
||||||
|
dns_server: backscatter.spameatingmonkey.net
|
||||||
|
website: https://spameatingmonkey.com/services
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: Spam Eating Monkey SEM-BLACK
|
||||||
|
dns_server: bl.spameatingmonkey.net
|
||||||
|
website: https://spameatingmonkey.com/services
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: Spam Eating Monkey SEM-IPV6BL
|
||||||
|
dns_server: bl.ipv6.spameatingmonkey.net
|
||||||
|
website: https://spameatingmonkey.com/services
|
||||||
|
ipv4: false
|
||||||
|
ipv6: true
|
||||||
|
domain: false
|
||||||
|
- name: SpamRATS! all
|
||||||
|
dns_server: all.spamrats.com
|
||||||
|
website: http://www.spamrats.com/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: PSBL (Passive Spam Block List)
|
||||||
|
dns_server: psbl.surriel.com
|
||||||
|
website: http://psbl.surriel.com/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: SWINOG
|
||||||
|
dns_server: dnsrbl.swinog.ch
|
||||||
|
website: https://antispam.imp.ch/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: GBUdb Truncate
|
||||||
|
dns_server: truncate.gbudb.net
|
||||||
|
website: http://www.gbudb.com/truncate/index.jsp
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: Weighted Private Block List
|
||||||
|
dns_server: db.wpbl.info
|
||||||
|
website: http://www.wpbl.info/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
# Used by GAFAM
|
||||||
|
- name: Composite Blocking List
|
||||||
|
dns_server: cbl.abuseat.org
|
||||||
|
website: cbl.abuseat.org
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
# Used by GAFAM
|
||||||
|
- name: SenderScore Blacklist
|
||||||
|
dns_server: bl.score.senderscore.com
|
||||||
|
website: https://senderscore.com
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
- name: Invaluement
|
||||||
|
dns_server: sip.invaluement.com
|
||||||
|
website: https://www.invaluement.com/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: false
|
||||||
|
domain: false
|
||||||
|
# Added cause it supports IPv6
|
||||||
|
- name: AntiCaptcha.NET IPv6
|
||||||
|
dns_server: dnsbl6.anticaptcha.net
|
||||||
|
website: http://anticaptcha.net/
|
||||||
|
ipv4: false
|
||||||
|
ipv6: true
|
||||||
|
domain: false
|
||||||
|
- name: SPFBL.net RBL
|
||||||
|
dns_server: dnsbl.spfbl.net
|
||||||
|
website: https://spfbl.net/en/dnsbl/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: true
|
||||||
|
domain: true
|
||||||
|
- name: Suomispam Blacklist
|
||||||
|
dns_server: bl.suomispam.net
|
||||||
|
website: http://suomispam.net/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: true
|
||||||
|
domain: false
|
||||||
|
- name: NordSpam
|
||||||
|
dns_server: bl.nordspam.com
|
||||||
|
website: https://www.nordspam.com/
|
||||||
|
ipv4: true
|
||||||
|
ipv6: true
|
||||||
|
domain: false
|
|
@ -1,4 +1,5 @@
|
||||||
VirtualHost "{{ domain }}"
|
VirtualHost "{{ domain }}"
|
||||||
|
enable = true
|
||||||
ssl = {
|
ssl = {
|
||||||
key = "/etc/yunohost/certs/{{ domain }}/key.pem";
|
key = "/etc/yunohost/certs/{{ domain }}/key.pem";
|
||||||
certificate = "/etc/yunohost/certs/{{ domain }}/crt.pem";
|
certificate = "/etc/yunohost/certs/{{ domain }}/crt.pem";
|
||||||
|
@ -13,3 +14,58 @@ VirtualHost "{{ domain }}"
|
||||||
namefield = "cn",
|
namefield = "cn",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- Discovery items
|
||||||
|
disco_items = {
|
||||||
|
{ "muc.{{ domain }}" },
|
||||||
|
{ "pubsub.{{ domain }}" },
|
||||||
|
{ "jabber.{{ domain }}" },
|
||||||
|
{ "vjud.{{ domain }}" },
|
||||||
|
{ "xmpp-upload.{{ domain }}" },
|
||||||
|
};
|
||||||
|
|
||||||
|
-- contact_info = {
|
||||||
|
-- abuse = { "mailto:abuse@{{ domain }}", "xmpp:admin@{{ domain }}" };
|
||||||
|
-- admin = { "mailto:root@{{ domain }}", "xmpp:admin@{{ domain }}" };
|
||||||
|
-- };
|
||||||
|
|
||||||
|
------ Components ------
|
||||||
|
-- You can specify components to add hosts that provide special services,
|
||||||
|
-- like multi-user conferences, and transports.
|
||||||
|
|
||||||
|
---Set up a MUC (multi-user chat) room server
|
||||||
|
Component "muc.{{ domain }}" "muc"
|
||||||
|
name = "{{ domain }} Chatrooms"
|
||||||
|
|
||||||
|
modules_enabled = {
|
||||||
|
"muc_limits";
|
||||||
|
"muc_log";
|
||||||
|
"muc_log_mam";
|
||||||
|
"muc_log_http";
|
||||||
|
"muc_vcard";
|
||||||
|
}
|
||||||
|
|
||||||
|
muc_event_rate = 0.5
|
||||||
|
muc_burst_factor = 10
|
||||||
|
|
||||||
|
---Set up a PubSub server
|
||||||
|
Component "pubsub.{{ domain }}" "pubsub"
|
||||||
|
name = "{{ domain }} Publish/Subscribe"
|
||||||
|
|
||||||
|
unrestricted_node_creation = true -- Anyone can create a PubSub node (from any server)
|
||||||
|
|
||||||
|
---Set up a HTTP Upload service
|
||||||
|
Component "xmpp-upload.{{ domain }}" "http_upload"
|
||||||
|
name = "{{ domain }} Sharing Service"
|
||||||
|
|
||||||
|
http_file_path = "/var/xmpp-upload/{{ domain }}/upload"
|
||||||
|
http_external_url = "https://xmpp-upload.{{ domain }}:443"
|
||||||
|
http_file_base_path = "/upload"
|
||||||
|
http_file_size_limit = 6*1024*1024
|
||||||
|
http_file_quota = 60*1024*1024
|
||||||
|
http_upload_file_size_limit = 100 * 1024 * 1024 -- bytes
|
||||||
|
http_upload_quota = 10 * 1024 * 1024 * 1024 -- bytes
|
||||||
|
|
||||||
|
---Set up a VJUD service
|
||||||
|
Component "vjud.{{ domain }}" "vjud"
|
||||||
|
vjud_disco_name = "{{ domain }} User Directory"
|
||||||
|
|
|
@ -81,14 +81,6 @@ http_interfaces = { "127.0.0.1", "::1" }
|
||||||
-- Enable IPv6
|
-- Enable IPv6
|
||||||
use_ipv6 = true
|
use_ipv6 = true
|
||||||
|
|
||||||
-- Discovery items
|
|
||||||
disco_items = {
|
|
||||||
{ "muc.{{ main_domain }}" },
|
|
||||||
{ "pubsub.{{ main_domain }}" },
|
|
||||||
{ "xmpp-upload.{{ main_domain }}" },
|
|
||||||
{ "vjud.{{ main_domain }}" }
|
|
||||||
};
|
|
||||||
|
|
||||||
-- BOSH configuration (mod_bosh)
|
-- BOSH configuration (mod_bosh)
|
||||||
consider_bosh_secure = true
|
consider_bosh_secure = true
|
||||||
cross_domain_bosh = true
|
cross_domain_bosh = true
|
||||||
|
@ -119,45 +111,6 @@ log = {
|
||||||
Component "localhost" "http"
|
Component "localhost" "http"
|
||||||
modules_enabled = { "bosh" }
|
modules_enabled = { "bosh" }
|
||||||
|
|
||||||
---Set up a MUC (multi-user chat) room server
|
|
||||||
Component "muc.{{ main_domain }}" "muc"
|
|
||||||
name = "{{ main_domain }} Chatrooms"
|
|
||||||
|
|
||||||
modules_enabled = {
|
|
||||||
"muc_limits";
|
|
||||||
"muc_log";
|
|
||||||
"muc_log_mam";
|
|
||||||
"muc_log_http";
|
|
||||||
"muc_vcard";
|
|
||||||
}
|
|
||||||
|
|
||||||
muc_event_rate = 0.5
|
|
||||||
muc_burst_factor = 10
|
|
||||||
|
|
||||||
---Set up a PubSub server
|
|
||||||
Component "pubsub.{{ main_domain }}" "pubsub"
|
|
||||||
name = "{{ main_domain }} Publish/Subscribe"
|
|
||||||
|
|
||||||
unrestricted_node_creation = true -- Anyone can create a PubSub node (from any server)
|
|
||||||
|
|
||||||
---Set up a HTTP Upload service
|
|
||||||
Component "xmpp-upload.{{ main_domain }}" "http_upload"
|
|
||||||
name = "{{ main_domain }} Sharing Service"
|
|
||||||
|
|
||||||
http_file_path = "/var/xmpp-upload/{{ main_domain }}/upload"
|
|
||||||
http_external_url = "https://xmpp-upload.{{ main_domain }}:443"
|
|
||||||
http_file_base_path = "/upload"
|
|
||||||
http_file_size_limit = 6*1024*1024
|
|
||||||
http_file_quota = 60*1024*1024
|
|
||||||
http_upload_file_size_limit = 100 * 1024 * 1024 -- bytes
|
|
||||||
http_upload_quota = 10 * 1024 * 1024 * 1024 -- bytes
|
|
||||||
|
|
||||||
|
|
||||||
---Set up a VJUD service
|
|
||||||
Component "vjud.{{ main_domain }}" "vjud"
|
|
||||||
ud_disco_name = "{{ main_domain }} User Directory"
|
|
||||||
|
|
||||||
|
|
||||||
----------- Virtual hosts -----------
|
----------- Virtual hosts -----------
|
||||||
-- You need to add a VirtualHost entry for each domain you wish Metronome to serve.
|
-- You need to add a VirtualHost entry for each domain you wish Metronome to serve.
|
||||||
-- Settings under each VirtualHost entry apply *only* to that host.
|
-- Settings under each VirtualHost entry apply *only* to that host.
|
||||||
|
|
|
@ -75,7 +75,7 @@ server {
|
||||||
root /dev/null;
|
root /dev/null;
|
||||||
|
|
||||||
location /upload/ {
|
location /upload/ {
|
||||||
alias /var/xmpp-upload/{{ domain }}/upload;
|
alias /var/xmpp-upload/{{ domain }}/upload/;
|
||||||
# Pass all requests to metronome, except for GET and HEAD requests.
|
# Pass all requests to metronome, except for GET and HEAD requests.
|
||||||
limit_except GET HEAD {
|
limit_except GET HEAD {
|
||||||
proxy_pass http://localhost:5290;
|
proxy_pass http://localhost:5290;
|
||||||
|
|
|
@ -33,14 +33,20 @@ smtpd_tls_cert_file = /etc/yunohost/certs/{{ main_domain }}/crt.pem
|
||||||
smtpd_tls_key_file = /etc/yunohost/certs/{{ main_domain }}/key.pem
|
smtpd_tls_key_file = /etc/yunohost/certs/{{ main_domain }}/key.pem
|
||||||
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
|
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
|
||||||
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
|
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
|
||||||
smtpd_tls_mandatory_ciphers = medium
|
# smtpd_tls_mandatory_ciphers = medium # (c.f. below)
|
||||||
|
|
||||||
# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam.pem
|
# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam.pem
|
||||||
# not actually 1024 bits, this applies to all DHE >= 1024 bits
|
# not actually 1024 bits, this applies to all DHE >= 1024 bits
|
||||||
# smtpd_tls_dh1024_param_file = /path/to/dhparam.pem
|
# smtpd_tls_dh1024_param_file = /path/to/dhparam.pem
|
||||||
|
|
||||||
tls_medium_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
|
# This custom medium cipherlist recommendation only works if we have a DH ... which we don't, c.f. https://github.com/YunoHost/issues/issues/93
|
||||||
|
# On the other hand, the postfix doc strongly discourage tweaking this list ... So whatever, let's keep the mandatory_ciphers to high like we did before applying the Mozilla recommendation ...
|
||||||
|
#tls_medium_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
|
||||||
tls_preempt_cipherlist = no
|
tls_preempt_cipherlist = no
|
||||||
|
|
||||||
|
# Custom Yunohost stuff ... because we can't use the recommendation about medium cipher list ...
|
||||||
|
smtpd_tls_mandatory_ciphers=high
|
||||||
|
smtpd_tls_eecdh_grade = ultra
|
||||||
###############################################################################
|
###############################################################################
|
||||||
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
|
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
|
||||||
smtpd_tls_loglevel=1
|
smtpd_tls_loglevel=1
|
||||||
|
|
|
@ -13,7 +13,7 @@ metronome:
|
||||||
category: xmpp
|
category: xmpp
|
||||||
mysql:
|
mysql:
|
||||||
log: [/var/log/mysql.log,/var/log/mysql.err,/var/log/mysql/error.log]
|
log: [/var/log/mysql.log,/var/log/mysql.err,/var/log/mysql/error.log]
|
||||||
alternates: ['mariadb']
|
actual_systemd_service: mariadb
|
||||||
category: database
|
category: database
|
||||||
nginx:
|
nginx:
|
||||||
log: /var/log/nginx
|
log: /var/log/nginx
|
||||||
|
@ -27,7 +27,7 @@ php7.0-fpm:
|
||||||
category: web
|
category: web
|
||||||
postfix:
|
postfix:
|
||||||
log: [/var/log/mail.log,/var/log/mail.err]
|
log: [/var/log/mail.log,/var/log/mail.err]
|
||||||
test_status: systemctl show postfix@- | grep -q "^SubState=running"
|
actual_systemd_service: postfix@-
|
||||||
needs_exposed_ports: [25, 587]
|
needs_exposed_ports: [25, 587]
|
||||||
category: email
|
category: email
|
||||||
redis-server:
|
redis-server:
|
||||||
|
|
40
debian/changelog
vendored
40
debian/changelog
vendored
|
@ -1,3 +1,32 @@
|
||||||
|
yunohost (3.8.1.1) testing; urgency=low
|
||||||
|
|
||||||
|
- [fix] Stupid issue about path in debian/install ...
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Sun, 19 Apr 2020 07:04:00 +0000
|
||||||
|
|
||||||
|
yunohost (3.8.1) testing; urgency=low
|
||||||
|
|
||||||
|
## Helpers (PHP, apt)
|
||||||
|
|
||||||
|
- New helpers for extra apt repo, PHP version install, and PHP fpm (#881, #928, #929)
|
||||||
|
- Pave the way to migration to php7.3 and future ones (#880, #926)
|
||||||
|
- Option in PHP helper to use a dedicated php service (#915)
|
||||||
|
|
||||||
|
## Diagnosis
|
||||||
|
|
||||||
|
- Many improvements in diagnosis mechanism (#923, #921, #940)
|
||||||
|
|
||||||
|
## Misc fixes, improvements
|
||||||
|
- custom_portal and custom_overlay redirect (#925)
|
||||||
|
- Improve systemd settings for slapd (#933)
|
||||||
|
- Spelling and typo corrections (#931)
|
||||||
|
- Improve translations for French, German, Catalan
|
||||||
|
|
||||||
|
Thanks to all contributors <3 ! (Kay0u, Maniack Crudelis, ljf, E.Gaspar,
|
||||||
|
xaloc33)
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Sun, 19 Apr 2020 06:20:00 +0000
|
||||||
|
|
||||||
yunohost (3.8.0) testing; urgency=low
|
yunohost (3.8.0) testing; urgency=low
|
||||||
|
|
||||||
# Major stuff
|
# Major stuff
|
||||||
|
@ -45,6 +74,17 @@ yunohost (3.8.0) testing; urgency=low
|
||||||
|
|
||||||
-- Kay0u <pierre@kayou.io> Thu, 09 Apr 2020 19:59:18 +0000
|
-- Kay0u <pierre@kayou.io> Thu, 09 Apr 2020 19:59:18 +0000
|
||||||
|
|
||||||
|
yunohost (3.7.1.2) stable; urgency=low
|
||||||
|
|
||||||
|
- [fix] Be more robust against some situation where some archives are corrupted
|
||||||
|
- [fix] Make nginx regen-conf more robust against broken config or service failing to start, show info to help debugging
|
||||||
|
- [fix] Force-flush the regen-conf for nginx domain conf when adding/removing a domain...
|
||||||
|
- [fix] app_map : Make sure to return / and not empty string for stuff on domain root
|
||||||
|
- [fix] Improve ynh_systemd_action to wait for fail2ban to reload
|
||||||
|
- [fix] Improper use of logger.exception in app.py leading to infamous weird "KeyError: label"
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 27 Apr 2020 23:50:00 +0000
|
||||||
|
|
||||||
yunohost (3.7.1.1) stable; urgency=low
|
yunohost (3.7.1.1) stable; urgency=low
|
||||||
|
|
||||||
- [fix] lxc uid number is limited to 65536 by default (0c9a4509)
|
- [fix] lxc uid number is limited to 65536 by default (0c9a4509)
|
||||||
|
|
1
debian/install
vendored
1
debian/install
vendored
|
@ -7,6 +7,7 @@ data/hooks/* /usr/share/yunohost/hooks/
|
||||||
data/other/yunoprompt.service /etc/systemd/system/
|
data/other/yunoprompt.service /etc/systemd/system/
|
||||||
data/other/password/* /usr/share/yunohost/other/password/
|
data/other/password/* /usr/share/yunohost/other/password/
|
||||||
data/other/dpkg-origins/yunohost /etc/dpkg/origins
|
data/other/dpkg-origins/yunohost /etc/dpkg/origins
|
||||||
|
data/other/dnsbl_list.yml /usr/share/yunohost/other/
|
||||||
data/other/* /usr/share/yunohost/yunohost-config/moulinette/
|
data/other/* /usr/share/yunohost/yunohost-config/moulinette/
|
||||||
data/templates/* /usr/share/yunohost/templates/
|
data/templates/* /usr/share/yunohost/templates/
|
||||||
data/helpers /usr/share/yunohost/
|
data/helpers /usr/share/yunohost/
|
||||||
|
|
|
@ -162,7 +162,7 @@
|
||||||
"app_action_broke_system": "يبدو أنّ هذا الإجراء أدّى إلى تحطيم هذه الخدمات المهمة: {services}",
|
"app_action_broke_system": "يبدو أنّ هذا الإجراء أدّى إلى تحطيم هذه الخدمات المهمة: {services}",
|
||||||
"diagnosis_basesystem_host": "هذا الخادم يُشغّل ديبيان {debian_version}",
|
"diagnosis_basesystem_host": "هذا الخادم يُشغّل ديبيان {debian_version}",
|
||||||
"diagnosis_basesystem_kernel": "هذا الخادم يُشغّل نواة لينكس {kernel_version}",
|
"diagnosis_basesystem_kernel": "هذا الخادم يُشغّل نواة لينكس {kernel_version}",
|
||||||
"diagnosis_basesystem_ynh_single_version": "{0} الإصدار: {1} ({2})",
|
"diagnosis_basesystem_ynh_single_version": "{package} الإصدار: {version} ({repo})",
|
||||||
"diagnosis_basesystem_ynh_main_version": "هذا الخادم يُشغّل YunoHost {main_version} ({repo})",
|
"diagnosis_basesystem_ynh_main_version": "هذا الخادم يُشغّل YunoHost {main_version} ({repo})",
|
||||||
"diagnosis_everything_ok": "كل شيء على ما يرام في {category}!",
|
"diagnosis_everything_ok": "كل شيء على ما يرام في {category}!",
|
||||||
"diagnosis_ip_connected_ipv4": "الخادم مُتّصل بالإنترنت عبر IPv4!",
|
"diagnosis_ip_connected_ipv4": "الخادم مُتّصل بالإنترنت عبر IPv4!",
|
||||||
|
|
|
@ -502,15 +502,16 @@
|
||||||
"permission_require_account": "El permís {permission} només té sentit per als usuaris que tenen un compte, i per tant no es pot activar per als visitants.",
|
"permission_require_account": "El permís {permission} només té sentit per als usuaris que tenen un compte, i per tant no es pot activar per als visitants.",
|
||||||
"app_remove_after_failed_install": "Eliminant l'aplicació després que hagi fallat la instal·lació…",
|
"app_remove_after_failed_install": "Eliminant l'aplicació després que hagi fallat la instal·lació…",
|
||||||
"diagnosis_basesystem_ynh_main_version": "El servidor funciona amb YunoHost {main_version} ({repo})",
|
"diagnosis_basesystem_ynh_main_version": "El servidor funciona amb YunoHost {main_version} ({repo})",
|
||||||
"diagnosis_ram_low": "El sistema només té {available_abs_MB} MB ({available_percent}%) de memòria RAM disponibles d'un total de {total_abs_MB} MB. Aneu amb compte.",
|
"diagnosis_ram_low": "El sistema només té {available} ({available_percent}%) de memòria RAM disponibles d'un total de {total}. Aneu amb compte.",
|
||||||
"diagnosis_swap_none": "El sistema no té swap. Hauríeu de considerar afegir un mínim de 256 MB de swap per evitar situacions en les que el sistema es queda sense memòria.",
|
"diagnosis_swap_none": "El sistema no té swap. Hauríeu de considerar afegir un mínim de {recommended} de swap per evitar situacions en les que el sistema es queda sense memòria.",
|
||||||
"diagnosis_regenconf_manually_modified": "El fitxer de configuració {file} ha estat modificat manualment.",
|
"diagnosis_regenconf_manually_modified": "El fitxer de configuració {file} ha estat modificat manualment.",
|
||||||
"diagnosis_security_vulnerable_to_meltdown_details": "Per arreglar-ho, hauríeu d'actualitzar i reiniciar el sistema per tal de carregar el nou nucli de linux (o contactar amb el proveïdor del servidor si no funciona). Vegeu https://meltdownattack.com/ per a més informació.",
|
"diagnosis_security_vulnerable_to_meltdown_details": "Per arreglar-ho, hauríeu d'actualitzar i reiniciar el sistema per tal de carregar el nou nucli de linux (o contactar amb el proveïdor del servidor si no funciona). Vegeu https://meltdownattack.com/ per a més informació.",
|
||||||
"diagnosis_http_could_not_diagnose": "No s'ha pogut diagnosticar si el domini és accessible des de l'exterior. Error: {error}",
|
"diagnosis_http_could_not_diagnose": "No s'ha pogut diagnosticar si el domini és accessible des de l'exterior.",
|
||||||
|
"diagnosis_http_could_not_diagnose_details": "Error: {error}",
|
||||||
"domain_cannot_remove_main_add_new_one": "No es pot eliminar «{domain:s}» ja que és el domini principal i únic domini, primer s'ha d'afegir un altre domini utilitzant «yunohost domain add <un-altre-domini.com>», i després fer-lo el domini principal amb «yunohost domain main-domain -n <un-altre-domini.com>» i després es pot eliminar el domini «{domain:s}» utilitzant «yunohost domain remove {domain:s}».",
|
"domain_cannot_remove_main_add_new_one": "No es pot eliminar «{domain:s}» ja que és el domini principal i únic domini, primer s'ha d'afegir un altre domini utilitzant «yunohost domain add <un-altre-domini.com>», i després fer-lo el domini principal amb «yunohost domain main-domain -n <un-altre-domini.com>» i després es pot eliminar el domini «{domain:s}» utilitzant «yunohost domain remove {domain:s}».",
|
||||||
"diagnosis_basesystem_host": "El servidor funciona amb Debian {debian_version}",
|
"diagnosis_basesystem_host": "El servidor funciona amb Debian {debian_version}",
|
||||||
"diagnosis_basesystem_kernel": "El servidor funciona amb el nucli de Linux {kernel_version}",
|
"diagnosis_basesystem_kernel": "El servidor funciona amb el nucli de Linux {kernel_version}",
|
||||||
"diagnosis_basesystem_ynh_single_version": "{0} versió: {1}({2})",
|
"diagnosis_basesystem_ynh_single_version": "{package} versió: {version}({repo})",
|
||||||
"diagnosis_basesystem_ynh_inconsistent_versions": "Esteu utilitzant versions inconsistents dels paquets de YunoHost… probablement a causa d'una actualització fallida o parcial.",
|
"diagnosis_basesystem_ynh_inconsistent_versions": "Esteu utilitzant versions inconsistents dels paquets de YunoHost… probablement a causa d'una actualització fallida o parcial.",
|
||||||
"diagnosis_display_tip_web": "Podeu anar a la secció de Diagnòstics (en la pantalla principal) per veure els errors que s'han trobat.",
|
"diagnosis_display_tip_web": "Podeu anar a la secció de Diagnòstics (en la pantalla principal) per veure els errors que s'han trobat.",
|
||||||
"diagnosis_failed_for_category": "Ha fallat el diagnòstic per la categoria «{category}»: {error}",
|
"diagnosis_failed_for_category": "Ha fallat el diagnòstic per la categoria «{category}»: {error}",
|
||||||
|
@ -535,16 +536,16 @@
|
||||||
"diagnosis_ip_weird_resolvconf_details": "En canvi, aquest fitxer hauria de ser un enllaç simbòlic cap a /etc/resolvconf/run/resolv.conf i que aquest apunti cap a 127.0.0.1 (dnsmasq). La configuració del «resolver» real s'hauria de fer a /etc/resolv.dnsmaq.conf.",
|
"diagnosis_ip_weird_resolvconf_details": "En canvi, aquest fitxer hauria de ser un enllaç simbòlic cap a /etc/resolvconf/run/resolv.conf i que aquest apunti cap a 127.0.0.1 (dnsmasq). La configuració del «resolver» real s'hauria de fer a /etc/resolv.dnsmaq.conf.",
|
||||||
"diagnosis_dns_good_conf": "Bona configuració DNS pel domini {domain} (categoria {category})",
|
"diagnosis_dns_good_conf": "Bona configuració DNS pel domini {domain} (categoria {category})",
|
||||||
"diagnosis_dns_bad_conf": "Configuració DNS incorrecta o inexistent pel domini {domain} (categoria {category})",
|
"diagnosis_dns_bad_conf": "Configuració DNS incorrecta o inexistent pel domini {domain} (categoria {category})",
|
||||||
"diagnosis_dns_missing_record": "Segons la configuració DNS recomanada, hauríeu d'afegir un registre DNS de tipus {0}, nom {1} i valor {2}. Hi ha més informació a https://yunohost.org/dns_config.",
|
"diagnosis_dns_missing_record": "Segons la configuració DNS recomanada, hauríeu d'afegir un registre DNS\ntipus: {type}\nnom: {name}\nvalor: {value}.",
|
||||||
"diagnosis_dns_discrepancy": "El registre DNS de tipus {0} i nom {1} no concorda amb la configuració recomanada. Valor actual: {2}. Valor esperat: {3}. Més informació a https://yunohost.org/dns_config.",
|
"diagnosis_dns_discrepancy": "El registre DNS de tipus {type} i nom {name} no concorda amb la configuració recomanada.\nValor actual: {current}\nValor esperat: {value}",
|
||||||
"diagnosis_services_bad_status": "El servei {service} està {status} :(",
|
"diagnosis_services_bad_status": "El servei {service} està {status} :(",
|
||||||
"diagnosis_diskusage_verylow": "El lloc d'emmagatzematge {mountpoint} (en l'aparell {device}) només té disponibles {free_abs_GB} GB ({free_percent}%). Hauríeu de considerar alliberar una mica d'espai.",
|
"diagnosis_diskusage_verylow": "El lloc d'emmagatzematge {mountpoint} (en l'aparell {device}) només té disponibles {free} ({free_percent}%). Hauríeu de considerar alliberar una mica d'espai.",
|
||||||
"diagnosis_diskusage_low": "El lloc d'emmagatzematge {mountpoint} (en l'aparell {device}) només té disponibles {free_abs_GB} GB ({free_percent}%). Aneu amb compte.",
|
"diagnosis_diskusage_low": "El lloc d'emmagatzematge {mountpoint} (en l'aparell {device}) només té disponibles {free} ({free_percent}%). Aneu amb compte.",
|
||||||
"diagnosis_diskusage_ok": "El lloc d'emmagatzematge {mountpoint} (en l'aparell {device}) encara té {free_abs_GB} GB ({free_percent}%) lliures!",
|
"diagnosis_diskusage_ok": "El lloc d'emmagatzematge {mountpoint} (en l'aparell {device}) encara té {free} ({free_percent}%) lliures!",
|
||||||
"diagnosis_ram_verylow": "El sistema només té {available_abs_MB} MB ({available_percent}%) de memòria RAM disponibles! (d'un total de {total_abs_MB} MB)",
|
"diagnosis_ram_verylow": "El sistema només té {available} ({available_percent}%) de memòria RAM disponibles! (d'un total de {total})",
|
||||||
"diagnosis_ram_ok": "El sistema encara té {available_abs_MB} MB ({available_percent}%) de memòria RAM disponibles d'un total de {total_abs_MB} MB.",
|
"diagnosis_ram_ok": "El sistema encara té {available} ({available_percent}%) de memòria RAM disponibles d'un total de {total}.",
|
||||||
"diagnosis_swap_notsomuch": "El sistema només té {total_MB} MB de swap. Hauríeu de considerar tenir un mínim de 256 MB per evitar situacions en les que el sistema es queda sense memòria.",
|
"diagnosis_swap_notsomuch": "El sistema només té {total} de swap. Hauríeu de considerar tenir un mínim de {recommended} per evitar situacions en les que el sistema es queda sense memòria.",
|
||||||
"diagnosis_swap_ok": "El sistema té {total_MB} MB de swap!",
|
"diagnosis_swap_ok": "El sistema té {total} de swap!",
|
||||||
"diagnosis_regenconf_allgood": "Tots els fitxers de configuració estan en acord amb la configuració recomanada!",
|
"diagnosis_regenconf_allgood": "Tots els fitxers de configuració estan en acord amb la configuració recomanada!",
|
||||||
"diagnosis_regenconf_manually_modified_details": "No hauria de ser cap problema sempre i quan sapigueu el que esteu fent ;) !",
|
"diagnosis_regenconf_manually_modified_details": "No hauria de ser cap problema sempre i quan sapigueu el que esteu fent ;) !",
|
||||||
"diagnosis_regenconf_manually_modified_debian": "El fitxer de configuració {file} ha estat modificat manualment respecte al fitxer per defecte de Debian.",
|
"diagnosis_regenconf_manually_modified_debian": "El fitxer de configuració {file} ha estat modificat manualment respecte al fitxer per defecte de Debian.",
|
||||||
|
@ -559,7 +560,8 @@
|
||||||
"diagnosis_description_ports": "Exposició dels ports",
|
"diagnosis_description_ports": "Exposició dels ports",
|
||||||
"diagnosis_description_regenconf": "Configuració del sistema",
|
"diagnosis_description_regenconf": "Configuració del sistema",
|
||||||
"diagnosis_description_security": "Verificacions de seguretat",
|
"diagnosis_description_security": "Verificacions de seguretat",
|
||||||
"diagnosis_ports_could_not_diagnose": "No s'ha pogut diagnosticar si els ports són accessibles des de l'exterior. Error: {error}",
|
"diagnosis_ports_could_not_diagnose": "No s'ha pogut diagnosticar si els ports són accessibles des de l'exterior.",
|
||||||
|
"diagnosis_ports_could_not_diagnose_details": "Error: {error}",
|
||||||
"diagnosis_ports_unreachable": "El port {port} no és accessible des de l'exterior.",
|
"diagnosis_ports_unreachable": "El port {port} no és accessible des de l'exterior.",
|
||||||
"diagnosis_ports_ok": "El port {port} és accessible des de l'exterior.",
|
"diagnosis_ports_ok": "El port {port} és accessible des de l'exterior.",
|
||||||
"diagnosis_http_ok": "El domini {domain} és accessible per mitjà de HTTP des de fora de la xarxa local.",
|
"diagnosis_http_ok": "El domini {domain} és accessible per mitjà de HTTP des de fora de la xarxa local.",
|
||||||
|
@ -571,22 +573,21 @@
|
||||||
"apps_catalog_obsolete_cache": "La memòria cau del catàleg d'aplicacions és buida o obsoleta.",
|
"apps_catalog_obsolete_cache": "La memòria cau del catàleg d'aplicacions és buida o obsoleta.",
|
||||||
"apps_catalog_update_success": "S'ha actualitzat el catàleg d'aplicacions!",
|
"apps_catalog_update_success": "S'ha actualitzat el catàleg d'aplicacions!",
|
||||||
"diagnosis_mail_ougoing_port_25_ok": "El port de sortida 25 no està bloquejat i els correus es poden enviar a altres servidors.",
|
"diagnosis_mail_ougoing_port_25_ok": "El port de sortida 25 no està bloquejat i els correus es poden enviar a altres servidors.",
|
||||||
"diagnosis_mail_ougoing_port_25_blocked": "Sembla que el port de sortida 25 està bloquejat. Hauríeu d'intentar desbloquejar-lo al panell de configuració del proveïdor d'accés a internet (o allotjador). Mentrestant, el servidor no podrà enviar correus a altres servidors.",
|
"diagnosis_mail_outgoing_port_25_blocked": "Sembla que el port de sortida 25 està bloquejat. Hauríeu d'intentar desbloquejar-lo al panell de configuració del proveïdor d'accés a internet (o allotjador). Mentrestant, el servidor no podrà enviar correus a altres servidors.",
|
||||||
"diagnosis_description_mail": "Correu electrònic",
|
"diagnosis_description_mail": "Correu electrònic",
|
||||||
"migration_description_0013_futureproof_apps_catalog_system": "Migrar al nou sistema de catàleg d'aplicacions resistent al pas del temps",
|
"migration_description_0013_futureproof_apps_catalog_system": "Migrar al nou sistema de catàleg d'aplicacions resistent al pas del temps",
|
||||||
"app_upgrade_script_failed": "Hi ha hagut un error en el script d'actualització de l'aplicació",
|
"app_upgrade_script_failed": "Hi ha hagut un error en el script d'actualització de l'aplicació",
|
||||||
"diagnosis_services_bad_status_tip": "Podeu intentar reiniciar el servei, i si no funciona, podeu mirar els registres del servei utilitzant «yunohost service log {0}» o a través de «Serveis» a la secció de la pàgina web d'administració.",
|
"diagnosis_services_bad_status_tip": "Podeu intentar reiniciar el servei, i si no funciona, podeu mirar els registres del servei utilitzant «yunohost service log {service}» o a través de «Serveis» a la secció de la pàgina web d'administració.",
|
||||||
"diagnosis_ports_forwarding_tip": "Per arreglar aquest problema, segurament s'ha de configurar el reenviament de ports en el router tal i com s'explica a https://yunohost.org/isp_box_config",
|
"diagnosis_ports_forwarding_tip": "Per arreglar aquest problema, segurament s'ha de configurar el reenviament de ports en el router tal i com s'explica a https://yunohost.org/isp_box_config",
|
||||||
"diagnosis_http_bad_status_code": "El sistema de diagnòstic no ha pogut connectar amb el servidor. Podria ser que una altra màquina hagi contestat en lloc del servidor. S'hauria de comprovar que el reenviament del port 80 sigui correcte, que la configuració NGINX està actualitzada i que el reverse-proxy no està interferint.",
|
"diagnosis_http_bad_status_code": "El sistema de diagnòstic no ha pogut connectar amb el servidor. Podria ser que una altra màquina hagi contestat en lloc del servidor. S'hauria de comprovar que el reenviament del port 80 sigui correcte, que la configuració NGINX està actualitzada i que el reverse-proxy no està interferint.",
|
||||||
"diagnosis_no_cache": "Encara no hi ha memòria cau pel diagnòstic de la categoria «{category}»",
|
"diagnosis_no_cache": "Encara no hi ha memòria cau pel diagnòstic de la categoria «{category}»",
|
||||||
"diagnosis_http_timeout": "S'ha exhaurit el temps d'esperar intentant connectar amb el servidor des de l'exterior. Sembla que no s'hi pot accedir. S'hauria de comprovar que el reenviament del port 80 és correcte, que NGINX funciona, i que el tallafocs no està interferint.",
|
"diagnosis_http_timeout": "S'ha exhaurit el temps d'esperar intentant connectar amb el servidor des de l'exterior. Sembla que no s'hi pot accedir. S'hauria de comprovar que el reenviament del port 80 és correcte, que NGINX funciona, i que el tallafocs no està interferint.",
|
||||||
"diagnosis_http_connection_error": "Error de connexió: no s'ha pogut connectar amb el domini demanat, segurament és inaccessible.",
|
"diagnosis_http_connection_error": "Error de connexió: no s'ha pogut connectar amb el domini demanat, segurament és inaccessible.",
|
||||||
"diagnosis_http_unknown_error": "Hi ha hagut un error intentant accedir al domini, segurament és inaccessible.",
|
|
||||||
"yunohost_postinstall_end_tip": "S'ha completat la post-instal·lació. Per acabar la configuració, considereu:\n - afegir un primer usuari a través de la secció «Usuaris» a la pàgina web d'administració (o emprant «yunohost user create <username>» a la línia d'ordres);\n - diagnosticar possibles problemes a través de la secció «Diagnòstics» a la pàgina web d'administració (o emprant «yunohost diagnosis run» a la línia d'ordres);\n - llegir les seccions «Finalizing your setup» i «Getting to know Yunohost» a la documentació per administradors: https://yunohost.org/admindoc.",
|
"yunohost_postinstall_end_tip": "S'ha completat la post-instal·lació. Per acabar la configuració, considereu:\n - afegir un primer usuari a través de la secció «Usuaris» a la pàgina web d'administració (o emprant «yunohost user create <username>» a la línia d'ordres);\n - diagnosticar possibles problemes a través de la secció «Diagnòstics» a la pàgina web d'administració (o emprant «yunohost diagnosis run» a la línia d'ordres);\n - llegir les seccions «Finalizing your setup» i «Getting to know Yunohost» a la documentació per administradors: https://yunohost.org/admindoc.",
|
||||||
"migration_description_0014_remove_app_status_json": "Eliminar els fitxers d'aplicació status.json heretats",
|
"migration_description_0014_remove_app_status_json": "Eliminar els fitxers d'aplicació status.json heretats",
|
||||||
"diagnosis_services_running": "El servei {service} s'està executant!",
|
"diagnosis_services_running": "El servei {service} s'està executant!",
|
||||||
"diagnosis_services_conf_broken": "La configuració pel servei {service} està trencada!",
|
"diagnosis_services_conf_broken": "La configuració pel servei {service} està trencada!",
|
||||||
"diagnosis_ports_needed_by": "És necessari exposar aquest port per a les funcions {1} (servei {0})",
|
"diagnosis_ports_needed_by": "És necessari exposar aquest port per a les funcions {category} (servei {service})",
|
||||||
"global_settings_setting_pop3_enabled": "Activa el protocol POP3 per al servidor de correu",
|
"global_settings_setting_pop3_enabled": "Activa el protocol POP3 per al servidor de correu",
|
||||||
"log_app_action_run": "Executa l'acció de l'aplicació «{}»",
|
"log_app_action_run": "Executa l'acció de l'aplicació «{}»",
|
||||||
"log_app_config_show_panel": "Mostra el taulell de configuració de l'aplicació «{}»",
|
"log_app_config_show_panel": "Mostra el taulell de configuració de l'aplicació «{}»",
|
||||||
|
|
|
@ -304,7 +304,7 @@
|
||||||
"app_upgrade_script_failed": "Es ist ein Fehler im App-Upgrade-Skript aufgetreten",
|
"app_upgrade_script_failed": "Es ist ein Fehler im App-Upgrade-Skript aufgetreten",
|
||||||
"diagnosis_basesystem_host": "Server läuft unter Debian {debian_version}.",
|
"diagnosis_basesystem_host": "Server läuft unter Debian {debian_version}.",
|
||||||
"diagnosis_basesystem_kernel": "Server läuft unter Linux-Kernel {kernel_version}",
|
"diagnosis_basesystem_kernel": "Server läuft unter Linux-Kernel {kernel_version}",
|
||||||
"diagnosis_basesystem_ynh_single_version": "{0} Version: {1} ({2})",
|
"diagnosis_basesystem_ynh_single_version": "{package} Version: {version} ({repo})",
|
||||||
"diagnosis_basesystem_ynh_main_version": "Server läuft YunoHost {main_version} ({repo})",
|
"diagnosis_basesystem_ynh_main_version": "Server läuft YunoHost {main_version} ({repo})",
|
||||||
"diagnosis_basesystem_ynh_inconsistent_versions": "Sie verwenden inkonsistente Versionen der YunoHost-Pakete... wahrscheinlich wegen eines fehlgeschlagenen oder teilweisen Upgrades.",
|
"diagnosis_basesystem_ynh_inconsistent_versions": "Sie verwenden inkonsistente Versionen der YunoHost-Pakete... wahrscheinlich wegen eines fehlgeschlagenen oder teilweisen Upgrades.",
|
||||||
"diagnosis_display_tip_web": "Sie können den Abschnitt Diagnose (im Startbildschirm) aufrufen, um die gefundenen Probleme anzuzeigen.",
|
"diagnosis_display_tip_web": "Sie können den Abschnitt Diagnose (im Startbildschirm) aufrufen, um die gefundenen Probleme anzuzeigen.",
|
||||||
|
|
107
locales/en.json
107
locales/en.json
|
@ -74,6 +74,8 @@
|
||||||
"backup_archive_name_exists": "A backup archive with this name already exists.",
|
"backup_archive_name_exists": "A backup archive with this name already exists.",
|
||||||
"backup_archive_name_unknown": "Unknown local backup archive named '{name:s}'",
|
"backup_archive_name_unknown": "Unknown local backup archive named '{name:s}'",
|
||||||
"backup_archive_open_failed": "Could not open the backup archive",
|
"backup_archive_open_failed": "Could not open the backup archive",
|
||||||
|
"backup_archive_cant_retrieve_info_json": "Could not load infos for archive '{archive}' ... The info.json cannot be retrieved (or is not a valid json).",
|
||||||
|
"backup_archive_corrupted": "It looks like the backup archive '{archive}' is corrupted : {error}",
|
||||||
"backup_archive_system_part_not_available": "System part '{part:s}' unavailable in this backup",
|
"backup_archive_system_part_not_available": "System part '{part:s}' unavailable in this backup",
|
||||||
"backup_archive_writing_error": "Could not add the files '{source:s}' (named in the archive '{dest:s}') to be backed up into the compressed archive '{archive:s}'",
|
"backup_archive_writing_error": "Could not add the files '{source:s}' (named in the archive '{dest:s}') to be backed up into the compressed archive '{archive:s}'",
|
||||||
"backup_ask_for_copying_if_needed": "Do you want to perform the backup using {size:s} MB temporarily? (This way is used since some files could not be prepared using a more efficient method.)",
|
"backup_ask_for_copying_if_needed": "Do you want to perform the backup using {size:s} MB temporarily? (This way is used since some files could not be prepared using a more efficient method.)",
|
||||||
|
@ -91,7 +93,6 @@
|
||||||
"backup_delete_error": "Could not delete '{path:s}'",
|
"backup_delete_error": "Could not delete '{path:s}'",
|
||||||
"backup_deleted": "Backup deleted",
|
"backup_deleted": "Backup deleted",
|
||||||
"backup_hook_unknown": "The backup hook '{hook:s}' is unknown",
|
"backup_hook_unknown": "The backup hook '{hook:s}' is unknown",
|
||||||
"backup_invalid_archive": "This is not a backup archive",
|
|
||||||
"backup_method_borg_finished": "Backup into Borg finished",
|
"backup_method_borg_finished": "Backup into Borg finished",
|
||||||
"backup_method_copy_finished": "Backup copy finalized",
|
"backup_method_copy_finished": "Backup copy finalized",
|
||||||
"backup_method_custom_finished": "Custom backup method '{method:s}' finished",
|
"backup_method_custom_finished": "Custom backup method '{method:s}' finished",
|
||||||
|
@ -110,7 +111,7 @@
|
||||||
"backup_unable_to_organize_files": "Could not use the quick method to organize files in the archive",
|
"backup_unable_to_organize_files": "Could not use the quick method to organize files in the archive",
|
||||||
"backup_with_no_backup_script_for_app": "The app '{app:s}' has no backup script. Ignoring.",
|
"backup_with_no_backup_script_for_app": "The app '{app:s}' has no backup script. Ignoring.",
|
||||||
"backup_with_no_restore_script_for_app": "The '{app:s}' has no restoration script, you will not be able to automatically restore the backup of this app.",
|
"backup_with_no_restore_script_for_app": "The '{app:s}' has no restoration script, you will not be able to automatically restore the backup of this app.",
|
||||||
"certmanager_acme_not_configured_for_domain": "Certificate for the domain '{domain:s}' does not appear to be correctly installed. Please run 'cert-install' for this domain first.",
|
"certmanager_acme_not_configured_for_domain": "The ACME challenge cannot be ran for {domain} right now because its nginx conf lacks the corresponding code snippet... Please make sure that your nginx configuration is up to date using `yunohost tools regen-conf nginx --dry-run --with-diff`.",
|
||||||
"certmanager_attempt_to_renew_nonLE_cert": "The certificate for the domain '{domain:s}' is not issued by Let's Encrypt. Cannot renew it automatically!",
|
"certmanager_attempt_to_renew_nonLE_cert": "The certificate for the domain '{domain:s}' is not issued by Let's Encrypt. Cannot renew it automatically!",
|
||||||
"certmanager_attempt_to_renew_valid_cert": "The certificate for the domain '{domain:s}' is not about to expire! (You may use --force if you know what you're doing)",
|
"certmanager_attempt_to_renew_valid_cert": "The certificate for the domain '{domain:s}' is not about to expire! (You may use --force if you know what you're doing)",
|
||||||
"certmanager_attempt_to_replace_valid_cert": "You are attempting to overwrite a good and valid certificate for domain {domain:s}! (Use --force to bypass)",
|
"certmanager_attempt_to_replace_valid_cert": "You are attempting to overwrite a good and valid certificate for domain {domain:s}! (Use --force to bypass)",
|
||||||
|
@ -140,13 +141,12 @@
|
||||||
"diagnosis_basesystem_hardware_board": "Server board model is {model}",
|
"diagnosis_basesystem_hardware_board": "Server board model is {model}",
|
||||||
"diagnosis_basesystem_host": "Server is running Debian {debian_version}",
|
"diagnosis_basesystem_host": "Server is running Debian {debian_version}",
|
||||||
"diagnosis_basesystem_kernel": "Server is running Linux kernel {kernel_version}",
|
"diagnosis_basesystem_kernel": "Server is running Linux kernel {kernel_version}",
|
||||||
"diagnosis_basesystem_ynh_single_version": "{0} version: {1} ({2})",
|
"diagnosis_basesystem_ynh_single_version": "{package} version: {version} ({repo})",
|
||||||
"diagnosis_basesystem_ynh_main_version": "Server is running YunoHost {main_version} ({repo})",
|
"diagnosis_basesystem_ynh_main_version": "Server is running YunoHost {main_version} ({repo})",
|
||||||
"diagnosis_basesystem_ynh_inconsistent_versions": "You are running inconsistent versions of the YunoHost packages... most probably because of a failed or partial upgrade.",
|
"diagnosis_basesystem_ynh_inconsistent_versions": "You are running inconsistent versions of the YunoHost packages... most probably because of a failed or partial upgrade.",
|
||||||
"diagnosis_display_tip_web": "You can go to the Diagnosis section (in the home screen) to see the issues found.",
|
"diagnosis_display_tip": "To see the issues found, you can go to the Diagnosis section of the webadmin, or run 'yunohost diagnosis show --issues' from the command-line.",
|
||||||
"diagnosis_display_tip_cli": "You can run 'yunohost diagnosis show --issues' to display the issues found.",
|
|
||||||
"diagnosis_failed_for_category": "Diagnosis failed for category '{category}': {error}",
|
"diagnosis_failed_for_category": "Diagnosis failed for category '{category}': {error}",
|
||||||
"diagnosis_cache_still_valid": "(Cache still valid for {category} diagnosis. Not re-diagnosing yet!)",
|
"diagnosis_cache_still_valid": "(Cache still valid for {category} diagnosis. Won't re-diagnose it yet!)",
|
||||||
"diagnosis_cant_run_because_of_dep": "Can't run diagnosis for {category} while there are important issues related to {dep}.",
|
"diagnosis_cant_run_because_of_dep": "Can't run diagnosis for {category} while there are important issues related to {dep}.",
|
||||||
"diagnosis_ignored_issues": "(+ {nb_ignored} ignored issue(s))",
|
"diagnosis_ignored_issues": "(+ {nb_ignored} ignored issue(s))",
|
||||||
"diagnosis_found_errors": "Found {errors} significant issue(s) related to {category}!",
|
"diagnosis_found_errors": "Found {errors} significant issue(s) related to {category}!",
|
||||||
|
@ -159,36 +159,63 @@
|
||||||
"diagnosis_ip_no_ipv4": "The server does not have working IPv4.",
|
"diagnosis_ip_no_ipv4": "The server does not have working IPv4.",
|
||||||
"diagnosis_ip_connected_ipv6": "The server is connected to the Internet through IPv6 !",
|
"diagnosis_ip_connected_ipv6": "The server is connected to the Internet through IPv6 !",
|
||||||
"diagnosis_ip_no_ipv6": "The server does not have working IPv6.",
|
"diagnosis_ip_no_ipv6": "The server does not have working IPv6.",
|
||||||
|
"diagnosis_ip_global": "Global IP: <code>{global}</code>",
|
||||||
|
"diagnosis_ip_local": "Local IP: <code>{local}</code>",
|
||||||
"diagnosis_ip_not_connected_at_all": "The server does not seem to be connected to the Internet at all!?",
|
"diagnosis_ip_not_connected_at_all": "The server does not seem to be connected to the Internet at all!?",
|
||||||
"diagnosis_ip_dnsresolution_working": "Domain name resolution is working!",
|
"diagnosis_ip_dnsresolution_working": "Domain name resolution is working!",
|
||||||
"diagnosis_ip_broken_dnsresolution": "Domain name resolution seems to be broken for some reason... Is a firewall blocking DNS requests ?",
|
"diagnosis_ip_broken_dnsresolution": "Domain name resolution seems to be broken for some reason... Is a firewall blocking DNS requests ?",
|
||||||
"diagnosis_ip_broken_resolvconf": "Domain name resolution seems to be broken on your server, which seems related to /etc/resolv.conf not pointing to 127.0.0.1.",
|
"diagnosis_ip_broken_resolvconf": "Domain name resolution seems to be broken on your server, which seems related to <code>/etc/resolv.conf</code> not pointing to <code>127.0.0.1</code>.",
|
||||||
"diagnosis_ip_weird_resolvconf": "DNS resolution seems to be working, but be careful that you seem to be using a custom /etc/resolv.conf.",
|
"diagnosis_ip_weird_resolvconf": "DNS resolution seems to be working, but it looks like you're using a custom <code>/etc/resolv.conf</code>.",
|
||||||
"diagnosis_ip_weird_resolvconf_details": "Instead, this file should be a symlink to /etc/resolvconf/run/resolv.conf itself pointing to 127.0.0.1 (dnsmasq). The actual resolvers should be configured in /etc/resolv.dnsmasq.conf.",
|
"diagnosis_ip_weird_resolvconf_details": "The file <code>/etc/resolv.conf</code> should be a symlink to <code>/etc/resolvconf/run/resolv.conf</code> itself pointing to <code>127.0.0.1</code> (dnsmasq). If you want to manually configure DNS resolvers, please edit <code>/etc/resolv.dnsmasq.conf</code>.",
|
||||||
"diagnosis_dns_good_conf": "Good DNS configuration for domain {domain} (category {category})",
|
"diagnosis_dns_good_conf": "DNS records are correctly configured for domain {domain} (category {category})",
|
||||||
"diagnosis_dns_bad_conf": "Bad or missing DNS configuration for domain {domain} (category {category})",
|
"diagnosis_dns_bad_conf": "Some DNS records are missing or incorrect for domain {domain} (category {category})",
|
||||||
"diagnosis_dns_missing_record": "According to the recommended DNS configuration, you should add a DNS record with type {0}, name {1} and value {2}. You can check https://yunohost.org/dns_config for more info.",
|
"diagnosis_dns_missing_record": "According to the recommended DNS configuration, you should add a DNS record with the following info.<br>Type: <code>{type}</code><br>Name: <code>{name}</code><br>Value: <code>{value}</code>",
|
||||||
"diagnosis_dns_discrepancy": "The DNS record with type {0} and name {1} does not match the recommended configuration. Current value: {2}. Excepted value: {3}. You can check https://yunohost.org/dns_config for more info.",
|
"diagnosis_dns_discrepancy": "The following DNS record does not seem to follow the recommended configuration:<br>Type: <code>{type}</code><br>Name: <code>{name}</code><br>Current value: <code>{current}</code><br>Excepted value: <code>{value}</code>",
|
||||||
|
"diagnosis_dns_point_to_doc": "Please check the documentation at <a href='https://yunohost.org/dns_config'>https://yunohost.org/dns_config</a> if you need help about configuring DNS records.",
|
||||||
"diagnosis_services_running": "Service {service} is running!",
|
"diagnosis_services_running": "Service {service} is running!",
|
||||||
"diagnosis_services_conf_broken": "Configuration is broken for service {service}!",
|
"diagnosis_services_conf_broken": "Configuration is broken for service {service}!",
|
||||||
"diagnosis_services_bad_status": "Service {service} is {status} :(",
|
"diagnosis_services_bad_status": "Service {service} is {status} :(",
|
||||||
"diagnosis_services_bad_status_tip": "You can try to restart the service, and if it doesn't work, have a look at the service logs using 'yunohost service log {0}' or through the 'Services' section of the webadmin.",
|
"diagnosis_services_bad_status_tip": "You can try to <a href='#/services/{service}'>restart the service</a>, and if it doesn't work, have a look at <a href='#/services/{service}'>the service logs in the webadmin</a> (from the command line, you can do this with <cmd>yunohost service restart {service}</cmd> and <cmd>yunohost service log {service}</cmd>).",
|
||||||
"diagnosis_diskusage_verylow": "Storage {mountpoint} (on device {device}) has only {free_abs_GB} GB ({free_percent}%) space remaining. You should really consider cleaning up some space.",
|
"diagnosis_diskusage_verylow": "Storage <code>{mountpoint}</code> (on device <code>{device}</code>) has only {free} ({free_percent}%) space remaining (out of {total}). You should really consider cleaning up some space!",
|
||||||
"diagnosis_diskusage_low": "Storage {mountpoint} (on device {device}) has only {free_abs_GB} GB ({free_percent}%) space remaining. Be careful.",
|
"diagnosis_diskusage_low": "Storage <code>{mountpoint}</code> (on device <code>{device}</code>) has only {free} ({free_percent}%) space remaining (out of {total}). Be careful.",
|
||||||
"diagnosis_diskusage_ok": "Storage {mountpoint} (on device {device}) still has {free_abs_GB} GB ({free_percent}%) space left!",
|
"diagnosis_diskusage_ok": "Storage <code>{mountpoint}</code> (on device <code>{device}</code>) still has {free} ({free_percent}%) space left (out of {total})!",
|
||||||
"diagnosis_ram_verylow": "The system has only {available_abs_MB} MB ({available_percent}%) RAM left! (out of {total_abs_MB} MB)",
|
"diagnosis_ram_verylow": "The system has only {available} ({available_percent}%) RAM available! (out of {total})",
|
||||||
"diagnosis_ram_low": "The system has {available_abs_MB} MB ({available_percent}%) RAM left out of {total_abs_MB} MB. Be careful.",
|
"diagnosis_ram_low": "The system has {available} ({available_percent}%) RAM available (out of {total}). Be careful.",
|
||||||
"diagnosis_ram_ok": "The system still has {available_abs_MB} MB ({available_percent}%) RAM left out of {total_abs_MB} MB.",
|
"diagnosis_ram_ok": "The system still has {available} ({available_percent}%) RAM available out of {total}.",
|
||||||
"diagnosis_swap_none": "The system has no swap at all. You should consider adding at least 256 MB of swap to avoid situations where the system runs out of memory.",
|
"diagnosis_swap_none": "The system has no swap at all. You should consider adding at least {recommended} of swap to avoid situations where the system runs out of memory.",
|
||||||
"diagnosis_swap_notsomuch": "The system has only {total_MB} MB swap. You should consider having at least 256 MB to avoid situations where the system runs out of memory.",
|
"diagnosis_swap_notsomuch": "The system has only {total} swap. You should consider having at least {recommended} to avoid situations where the system runs out of memory.",
|
||||||
"diagnosis_swap_ok": "The system has {total_MB} MB of swap!",
|
"diagnosis_swap_ok": "The system has {total} of swap!",
|
||||||
"diagnosis_mail_ougoing_port_25_ok": "Outgoing port 25 is not blocked and email can be sent to other servers.",
|
"diagnosis_mail_outgoing_port_25_ok": "The SMTP mail server is able to send emails (outgoing port 25 is not blocked).",
|
||||||
"diagnosis_mail_ougoing_port_25_blocked": "Outgoing port 25 appears to be blocked. You should try to unblock it in your internet service provider (or hosting provider) configuration panel. Meanwhile, the server won't be able to send emails to other servers.",
|
"diagnosis_mail_outgoing_port_25_blocked": "The SMTP mail server cannot send emails to other servers because outgoing port 25 is blocked in IPv{ipversion}.",
|
||||||
|
"diagnosis_mail_outgoing_port_25_blocked_details": "You should first try to unblock outgoing port 25 in your internet router interface or your hosting provider interface. (Some hosting provider may require you to send them a support ticket for this).",
|
||||||
|
"diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "Some providers won't let you unblock outgoing port 25 because they don't care about Net Neutrality.<br> - Some of them provide the alternative of <a href='https://yunohost.org/#/smtp_relay'>using a mail server relay</a> though it implies that the relay will be able to spy on your email traffic.<br>- A privacy-friendly alternative is to use a VPN *with a dedicated public IP* to bypass this kind of limits. See <a href='https://yunohost.org/#/vpn_advantage'>https://yunohost.org/#/vpn_advantage</a><br>- You can also consider switching to <a href='https://yunohost.org/#/isp'>a more net neutrality-friendly provider</a>",
|
||||||
|
"diagnosis_mail_ehlo_ok": "The SMTP mail server is reachable from the outside and therefore is able to receive emails!",
|
||||||
|
"diagnosis_mail_ehlo_unreachable": "The SMTP mail server is unreachable from the outside on IPv{ipversion}. It won't be able to receive emails.",
|
||||||
|
"diagnosis_mail_ehlo_unreachable_details": "Could not open a connection on port 25 to your server in IPv{ipversion}. It appears to be unreachable.<br>1. The most common cause for this issue is that port 25 <a href='https://yunohost.org/isp_box_config'>is not correctly forwarded to your server</a>.<br>2. You should also make sure that service postfix is running.<br>3. On more complex setups: make sure that no firewall or reverse-proxy is interfering.",
|
||||||
|
"diagnosis_mail_ehlo_bad_answer": "A non-SMTP service answered on port 25 on IPv{ipversion}",
|
||||||
|
"diagnosis_mail_ehlo_bad_answer_details": "It could be due to an other machine answering instead of your server.",
|
||||||
|
"diagnosis_mail_ehlo_wrong": "A different SMTP mail server answers on IPv{ipversion}. It will probably not be able to receive emails.",
|
||||||
|
"diagnosis_mail_ehlo_wrong_details": "The EHLO received by the remote diagnoser in IPv{ipversion} is different from your server's domain.<br>Received EHLO: <code>{wrong_ehlo}</code><br>Expected: {right_ehlo}<br>The most common cause for this issue is that port 25 <a href='https://yunohost.org/isp_box_config'>is not correctly forwarded to your server</a>. Alternatively, make sure that no firewall or reverse-proxy is interfering.",
|
||||||
|
"diagnosis_mail_ehlo_could_not_diagnose": "Could not diagnose if postfix mail server is reachable from outside in IPv{ipversion}.",
|
||||||
|
"diagnosis_mail_ehlo_could_not_diagnose_details": "Error: {error}",
|
||||||
|
"diagnosis_mail_fcrdns_ok": "Your reverse DNS is correctly configured!",
|
||||||
|
"diagnosis_mail_fcrdns_dns_missing": "No reverse DNS is defined in IPv{ipversion}. Some emails may fail to get delivered or may get flagged as spam.",
|
||||||
|
"diagnosis_mail_fcrdns_nok_details": "You should first try to configure the reverse DNS with <code>{ehlo_domain}</code> in your internet router interface or your hosting provider interface. (Some hosting provider may require you to send them a support ticket for this).",
|
||||||
|
"diagnosis_mail_fcrdns_nok_alternatives_4": "Some providers won't let you configure your reverse DNS (or their feature might be broken...). If you are experiencing issues because of this, consider the following solutions:<br> - Some ISP provide the alternative of <a href='https://yunohost.org/#/smtp_relay'>using a mail server relay</a> though it implies that the relay will be able to spy on your email traffic.<br>- A privacy-friendly alternative is to use a VPN *with a dedicated public IP* to bypass this kind of limits. See <a href='https://yunohost.org/#/vpn_advantage'>https://yunohost.org/#/vpn_advantage</a><br>- Finally, it's also possible to <a href='https://yunohost.org/#/isp'>change of provider</a>",
|
||||||
|
"diagnosis_mail_fcrdns_nok_alternatives_6": "Some providers won't let you configure your reverse DNS (or their feature might be broken...). If your reverse DNS is correctly configured for IPv4, you can try disabling the use of IPv6 when sending emails by running <cmd>yunohost settings set smtp.allow_ipv6 -v off</cmd>. Note: this last solution means that you won't be able to send or receive emails from the few IPv6-only servers out there.",
|
||||||
|
"diagnosis_mail_fcrdns_different_from_ehlo_domain": "The reverse DNS is not correctly configured in IPv{ipversion}. Some emails may fail to get delivered or may get flagged as spam.",
|
||||||
|
"diagnosis_mail_fcrdns_different_from_ehlo_domain_details": "Current reverse DNS: <code>{rdns_domain}</code><br>Expected value: <code>{ehlo_domain}</code>",
|
||||||
|
"diagnosis_mail_blacklist_ok": "The IPs and domains used by this server do not appear to be blacklisted",
|
||||||
|
"diagnosis_mail_blacklist_listed_by": "Your IP or domain <code>{item}</code> is blacklisted on {blacklist_name}",
|
||||||
|
"diagnosis_mail_blacklist_reason": "The blacklist reason is: {reason}",
|
||||||
|
"diagnosis_mail_blacklist_website": "After identifying why you are listed and fixed it, feel free to ask for delisting on {blacklist_website}",
|
||||||
|
"diagnosis_mail_queue_ok": "{nb_pending} pending emails in the mail queues",
|
||||||
|
"diagnosis_mail_queue_unavailable": "Can not consult number of pending emails in queue",
|
||||||
|
"diagnosis_mail_queue_unavailable_details": "Error: {error}",
|
||||||
|
"diagnosis_mail_queue_too_big": "Too many pending emails in mail queue ({nb_pending} emails)",
|
||||||
"diagnosis_regenconf_allgood": "All configurations files are in line with the recommended configuration!",
|
"diagnosis_regenconf_allgood": "All configurations files are in line with the recommended configuration!",
|
||||||
"diagnosis_regenconf_manually_modified": "Configuration file {file} was manually modified.",
|
"diagnosis_regenconf_manually_modified": "Configuration file <code>{file}</code> appears to have been manually modified.",
|
||||||
"diagnosis_regenconf_manually_modified_details": "This is probably OK as long as you know what you're doing ;) !",
|
"diagnosis_regenconf_manually_modified_details": "This is probably OK if you know what you're doing! YunoHost will stop updating this file automatically... But beware that YunoHost upgrades could contain important recommended changes. If you want to, you can inspect the differences with <cmd>yunohost tools regen-conf {category} --dry-run --with-diff</cmd> and force the reset to the recommended configuration with <cmd>yunohost tools regen-conf {category} --force</cmd>",
|
||||||
"diagnosis_regenconf_manually_modified_debian": "Configuration file {file} was manually modified compared to Debian's default.",
|
|
||||||
"diagnosis_regenconf_manually_modified_debian_details": "This may probably be OK, but gotta keep an eye on it...",
|
|
||||||
"diagnosis_security_all_good": "No critical security vulnerability was found.",
|
"diagnosis_security_all_good": "No critical security vulnerability was found.",
|
||||||
"diagnosis_security_vulnerable_to_meltdown": "You appear vulnerable to the Meltdown criticial security vulnerability",
|
"diagnosis_security_vulnerable_to_meltdown": "You appear vulnerable to the Meltdown criticial security vulnerability",
|
||||||
"diagnosis_security_vulnerable_to_meltdown_details": "To fix this, you should upgrade your system and reboot to load the new linux kernel (or contact your server provider if this doesn't work). See https://meltdownattack.com/ for more infos.",
|
"diagnosis_security_vulnerable_to_meltdown_details": "To fix this, you should upgrade your system and reboot to load the new linux kernel (or contact your server provider if this doesn't work). See https://meltdownattack.com/ for more infos.",
|
||||||
|
@ -202,18 +229,25 @@
|
||||||
"diagnosis_description_mail": "Email",
|
"diagnosis_description_mail": "Email",
|
||||||
"diagnosis_description_regenconf": "System configurations",
|
"diagnosis_description_regenconf": "System configurations",
|
||||||
"diagnosis_description_security": "Security checks",
|
"diagnosis_description_security": "Security checks",
|
||||||
"diagnosis_ports_could_not_diagnose": "Could not diagnose if ports are reachable from outside. Error: {error}",
|
"diagnosis_ports_could_not_diagnose": "Could not diagnose if ports are reachable from outside in IPv{ipversion}.",
|
||||||
|
"diagnosis_ports_could_not_diagnose_details": "Error: {error}",
|
||||||
"diagnosis_ports_unreachable": "Port {port} is not reachable from outside.",
|
"diagnosis_ports_unreachable": "Port {port} is not reachable from outside.",
|
||||||
|
"diagnosis_ports_partially_unreachable": "Port {port} is not reachable from outside in IPv{failed}.",
|
||||||
"diagnosis_ports_ok": "Port {port} is reachable from outside.",
|
"diagnosis_ports_ok": "Port {port} is reachable from outside.",
|
||||||
"diagnosis_ports_needed_by": "Exposing this port is needed for {1} features (service {0})",
|
"diagnosis_ports_needed_by": "Exposing this port is needed for {category} features (service {service})",
|
||||||
"diagnosis_ports_forwarding_tip": "To fix this issue, you most probably need to configure port forwarding on your internet router as described in https://yunohost.org/isp_box_config",
|
"diagnosis_ports_forwarding_tip": "To fix this issue, you most probably need to configure port forwarding on your internet router as described in <a href='https://yunohost.org/isp_box_config'>https://yunohost.org/isp_box_config</a>",
|
||||||
"diagnosis_http_could_not_diagnose": "Could not diagnose if domain is reachable from outside. Error: {error}",
|
"diagnosis_http_hairpinning_issue": "Your local network does not seem to have hairpinning enabled.",
|
||||||
|
"diagnosis_http_hairpinning_issue_details": "This is probably because of your ISP box / router. As a result, people from outside your local network will be able to access your server as expected, but not people from inside the local network (like you, probably?). You may be able to improve the situation by having a look at <a href='https://yunohost.org/dns_local_network'>https://yunohost.org/dns_local_network</a>",
|
||||||
|
"diagnosis_http_could_not_diagnose": "Could not diagnose if domains are reachable from outside in IPv{ipversion}.",
|
||||||
|
"diagnosis_http_could_not_diagnose_details": "Error: {error}",
|
||||||
"diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.",
|
"diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.",
|
||||||
"diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable. You should check that you're correctly forwarding port 80, that nginx is running, and that a firewall is not interfering.",
|
"diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable.<br>1. The most common cause for this issue is that port 80 (and 443) <a href='https://yunohost.org/isp_box_config'>are not correctly forwarded to your server</a>.<br>2. You should also make sure that the service nginx is running<br>3. On more complex setups: make sure that no firewall or reverse-proxy is interfering.",
|
||||||
"diagnosis_http_connection_error": "Connection error: could not connect to the requested domain, it's very likely unreachable.",
|
"diagnosis_http_connection_error": "Connection error: could not connect to the requested domain, it's very likely unreachable.",
|
||||||
"diagnosis_http_unknown_error": "An error happened while trying to reach your domain, it's very likely unreachable.",
|
"diagnosis_http_bad_status_code": "It looks like another machine (maybe your internet router) answered instead of your server.<br>1. The most common cause for this issue is that port 80 (and 443) <a href='https://yunohost.org/isp_box_config'>are not correctly forwarded to your server</a>.<br>2. On more complex setups: make sure that no firewall or reverse-proxy is interfering.",
|
||||||
"diagnosis_http_bad_status_code": "The diagnosis system could not reach your server. It might be that another machine answered instead of your server. You should check that you're correctly forwarding port 80, that your nginx configuration is up to date, and that a reverse-proxy is not interfering.",
|
|
||||||
"diagnosis_http_unreachable": "Domain {domain} appears unreachable through HTTP from outside the local network.",
|
"diagnosis_http_unreachable": "Domain {domain} appears unreachable through HTTP from outside the local network.",
|
||||||
|
"diagnosis_http_partially_unreachable": "Domain {domain} appears unreachable through HTTP from outside the local network in IPv{failed}, though it works in IPv{passed}.",
|
||||||
|
"diagnosis_http_nginx_conf_not_up_to_date": "This domain's nginx configuration appears to have been modified manually, and prevents YunoHost from diagnosing if it's reachable on HTTP.",
|
||||||
|
"diagnosis_http_nginx_conf_not_up_to_date_details": "To fix the situation, inspect the difference with the command line using <cmd>yunohost tools regen-conf nginx --dry-run --with-diff</cmd> and if you're ok, apply the changes with <cmd>yunohost tools regen-conf nginx --force</cmd>.",
|
||||||
"diagnosis_unknown_categories": "The following categories are unknown: {categories}",
|
"diagnosis_unknown_categories": "The following categories are unknown: {categories}",
|
||||||
"diagnosis_never_ran_yet": "It looks like this server was setup recently and there's no diagnosis report to show yet. You should start by running a full diagnosis, either from the webadmin or using 'yunohost diagnosis run' from the command line.",
|
"diagnosis_never_ran_yet": "It looks like this server was setup recently and there's no diagnosis report to show yet. You should start by running a full diagnosis, either from the webadmin or using 'yunohost diagnosis run' from the command line.",
|
||||||
"domain_cannot_remove_main": "You cannot remove '{domain:s}' since it's the main domain, you first need to set another domain as the main domain using 'yunohost domain main-domain -n <another-domain>'; here is the list of candidate domains: {other_domains:s}",
|
"domain_cannot_remove_main": "You cannot remove '{domain:s}' since it's the main domain, you first need to set another domain as the main domain using 'yunohost domain main-domain -n <another-domain>'; here is the list of candidate domains: {other_domains:s}",
|
||||||
|
@ -279,6 +313,7 @@
|
||||||
"global_settings_setting_security_postfix_compatibility": "Compatibility vs. security tradeoff for the Postfix server. Affects the ciphers (and other security-related aspects)",
|
"global_settings_setting_security_postfix_compatibility": "Compatibility vs. security tradeoff for the Postfix server. Affects the ciphers (and other security-related aspects)",
|
||||||
"global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discard it and save it in /etc/yunohost/settings-unknown.json",
|
"global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discard it and save it in /etc/yunohost/settings-unknown.json",
|
||||||
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Allow the use of (deprecated) DSA hostkey for the SSH daemon configuration",
|
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Allow the use of (deprecated) DSA hostkey for the SSH daemon configuration",
|
||||||
|
"global_settings_setting_smtp_allow_ipv6": "Allow the use of IPv6 to receive and send mail",
|
||||||
"global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it is not a type supported by the system.",
|
"global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it is not a type supported by the system.",
|
||||||
"good_practices_about_admin_password": "You are now about to define a new administration password. The password should be at least 8 characters long—though it is good practice to use a longer password (i.e. a passphrase) and/or to use a variation of characters (uppercase, lowercase, digits and special characters).",
|
"good_practices_about_admin_password": "You are now about to define a new administration password. The password should be at least 8 characters long—though it is good practice to use a longer password (i.e. a passphrase) and/or to use a variation of characters (uppercase, lowercase, digits and special characters).",
|
||||||
"good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters long—though it is good practice to use a longer password (i.e. a passphrase) and/or to a variation of characters (uppercase, lowercase, digits and special characters).",
|
"good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters long—though it is good practice to use a longer password (i.e. a passphrase) and/or to a variation of characters (uppercase, lowercase, digits and special characters).",
|
||||||
|
|
|
@ -504,7 +504,7 @@
|
||||||
"apps_catalog_obsolete_cache": "La kaŝmemoro de la katalogo de programoj estas malplena aŭ malaktuala.",
|
"apps_catalog_obsolete_cache": "La kaŝmemoro de la katalogo de programoj estas malplena aŭ malaktuala.",
|
||||||
"apps_catalog_update_success": "La aplika katalogo estis ĝisdatigita!",
|
"apps_catalog_update_success": "La aplika katalogo estis ĝisdatigita!",
|
||||||
"diagnosis_basesystem_kernel": "Servilo funkcias Linuksan kernon {kernel_version}",
|
"diagnosis_basesystem_kernel": "Servilo funkcias Linuksan kernon {kernel_version}",
|
||||||
"diagnosis_basesystem_ynh_single_version": "{0} versio: {1} ({2})",
|
"diagnosis_basesystem_ynh_single_version": "{package} versio: {version} ({repo})",
|
||||||
"diagnosis_basesystem_ynh_main_version": "Servilo funkcias YunoHost {main_version} ({repo})",
|
"diagnosis_basesystem_ynh_main_version": "Servilo funkcias YunoHost {main_version} ({repo})",
|
||||||
"diagnosis_basesystem_ynh_inconsistent_versions": "Vi prizorgas malkonsekvencajn versiojn de la YunoHost-pakoj... plej probable pro malsukcesa aŭ parta ĝisdatigo.",
|
"diagnosis_basesystem_ynh_inconsistent_versions": "Vi prizorgas malkonsekvencajn versiojn de la YunoHost-pakoj... plej probable pro malsukcesa aŭ parta ĝisdatigo.",
|
||||||
"diagnosis_display_tip_web": "Vi povas iri al la sekcio Diagnozo (en la hejmekrano) por vidi la trovitajn problemojn.",
|
"diagnosis_display_tip_web": "Vi povas iri al la sekcio Diagnozo (en la hejmekrano) por vidi la trovitajn problemojn.",
|
||||||
|
@ -513,9 +513,9 @@
|
||||||
"diagnosis_display_tip_cli": "Vi povas aranĝi 'yunohost diagnosis show --issues' por aperigi la trovitajn problemojn.",
|
"diagnosis_display_tip_cli": "Vi povas aranĝi 'yunohost diagnosis show --issues' por aperigi la trovitajn problemojn.",
|
||||||
"diagnosis_failed_for_category": "Diagnozo malsukcesis por kategorio '{category}': {error}",
|
"diagnosis_failed_for_category": "Diagnozo malsukcesis por kategorio '{category}': {error}",
|
||||||
"app_upgrade_script_failed": "Eraro okazis en la skripto pri ĝisdatiga programo",
|
"app_upgrade_script_failed": "Eraro okazis en la skripto pri ĝisdatiga programo",
|
||||||
"diagnosis_diskusage_verylow": "Stokado {mountpoint} (sur aparato {device)) restas nur {free_abs_GB} GB ({free_percent}%) spaco. Vi vere konsideru purigi iom da spaco.",
|
"diagnosis_diskusage_verylow": "Stokado {mountpoint} (sur aparato {device)) restas nur {free} ({free_percent}%) spaco. Vi vere konsideru purigi iom da spaco.",
|
||||||
"diagnosis_ram_verylow": "La sistemo nur restas {available_abs_MB} MB ({available_percent}%) RAM! (el {total_abs_MB} MB)",
|
"diagnosis_ram_verylow": "La sistemo nur restas {available} ({available_percent}%) RAM! (el {total})",
|
||||||
"diagnosis_mail_ougoing_port_25_blocked": "Eliranta haveno 25 ŝajnas esti blokita. Vi devas provi malŝlosi ĝin en via agorda panelo de provizanto (aŭ gastiganto). Dume la servilo ne povos sendi retpoŝtojn al aliaj serviloj.",
|
"diagnosis_mail_outgoing_port_25_blocked": "Eliranta haveno 25 ŝajnas esti blokita. Vi devas provi malŝlosi ĝin en via agorda panelo de provizanto (aŭ gastiganto). Dume la servilo ne povos sendi retpoŝtojn al aliaj serviloj.",
|
||||||
"diagnosis_http_bad_status_code": "Ne povis atingi vian servilon kiel atendite, ĝi redonis malbonan statuskodon. Povas esti, ke alia maŝino respondis anstataŭ via servilo. Vi devus kontroli, ke vi ĝuste redonas la havenon 80, ke via nginx-agordo ĝisdatigas kaj ke reverso-prokuro ne interbatalas.",
|
"diagnosis_http_bad_status_code": "Ne povis atingi vian servilon kiel atendite, ĝi redonis malbonan statuskodon. Povas esti, ke alia maŝino respondis anstataŭ via servilo. Vi devus kontroli, ke vi ĝuste redonas la havenon 80, ke via nginx-agordo ĝisdatigas kaj ke reverso-prokuro ne interbatalas.",
|
||||||
"main_domain_changed": "La ĉefa domajno estis ŝanĝita",
|
"main_domain_changed": "La ĉefa domajno estis ŝanĝita",
|
||||||
"yunohost_postinstall_end_tip": "La post-instalado finiĝis! Por fini vian agordon, bonvolu konsideri:\n - aldonado de unua uzanto tra la sekcio 'Uzantoj' de la retadreso (aŭ 'yunohost user create <username>' en komandlinio);\n - diagnozi problemojn atendantajn solvi por ke via servilo funkciu kiel eble plej glate tra la sekcio 'Diagnosis' de la retadministrado (aŭ 'yunohost diagnosis run' en komandlinio);\n - legante la partojn 'Finigi vian agordon' kaj 'Ekkoni Yunohost' en la administra dokumentado: https://yunohost.org/admindoc.",
|
"yunohost_postinstall_end_tip": "La post-instalado finiĝis! Por fini vian agordon, bonvolu konsideri:\n - aldonado de unua uzanto tra la sekcio 'Uzantoj' de la retadreso (aŭ 'yunohost user create <username>' en komandlinio);\n - diagnozi problemojn atendantajn solvi por ke via servilo funkciu kiel eble plej glate tra la sekcio 'Diagnosis' de la retadministrado (aŭ 'yunohost diagnosis run' en komandlinio);\n - legante la partojn 'Finigi vian agordon' kaj 'Ekkoni Yunohost' en la administra dokumentado: https://yunohost.org/admindoc.",
|
||||||
|
@ -530,9 +530,9 @@
|
||||||
"diagnosis_ip_weird_resolvconf_details": "Anstataŭe, ĉi tiu dosiero estu ligilo kun /etc/resolvconf/run/resolv.conf mem montrante al 127.0.0.1 (dnsmasq). La efektivaj solvantoj devas agordi per /etc/resolv.dnsmasq.conf.",
|
"diagnosis_ip_weird_resolvconf_details": "Anstataŭe, ĉi tiu dosiero estu ligilo kun /etc/resolvconf/run/resolv.conf mem montrante al 127.0.0.1 (dnsmasq). La efektivaj solvantoj devas agordi per /etc/resolv.dnsmasq.conf.",
|
||||||
"diagnosis_dns_good_conf": "Bona DNS-agordo por domajno {domain} (kategorio {category})",
|
"diagnosis_dns_good_conf": "Bona DNS-agordo por domajno {domain} (kategorio {category})",
|
||||||
"diagnosis_dns_bad_conf": "Malbona / mankas DNS-agordo por domajno {domain} (kategorio {category})",
|
"diagnosis_dns_bad_conf": "Malbona / mankas DNS-agordo por domajno {domain} (kategorio {category})",
|
||||||
"diagnosis_ram_ok": "La sistemo ankoraŭ havas {available_abs_MB} MB ({available_percent}%) RAM forlasita de {total_abs_MB} MB.",
|
"diagnosis_ram_ok": "La sistemo ankoraŭ havas {available} ({available_percent}%) RAM forlasita de {total}.",
|
||||||
"diagnosis_swap_none": "La sistemo tute ne havas interŝanĝon. Vi devus pripensi aldoni almenaŭ 256 MB da interŝanĝo por eviti situaciojn en kiuj la sistemo restas sen memoro.",
|
"diagnosis_swap_none": "La sistemo tute ne havas interŝanĝon. Vi devus pripensi aldoni almenaŭ {recommended} da interŝanĝo por eviti situaciojn en kiuj la sistemo restas sen memoro.",
|
||||||
"diagnosis_swap_notsomuch": "La sistemo havas nur {total_MB} MB-interŝanĝon. Vi konsideru havi almenaŭ 256 MB por eviti situaciojn en kiuj la sistemo restas sen memoro.",
|
"diagnosis_swap_notsomuch": "La sistemo havas nur {total}-interŝanĝon. Vi konsideru havi almenaŭ {recommended} por eviti situaciojn en kiuj la sistemo restas sen memoro.",
|
||||||
"diagnosis_regenconf_manually_modified_details": "Ĉi tio probable estas bona tiel longe kiel vi scias kion vi faras;)!",
|
"diagnosis_regenconf_manually_modified_details": "Ĉi tio probable estas bona tiel longe kiel vi scias kion vi faras;)!",
|
||||||
"diagnosis_regenconf_manually_modified_debian": "Agordodosiero {file} estis modifita permane kompare kun la defaŭlta Debian.",
|
"diagnosis_regenconf_manually_modified_debian": "Agordodosiero {file} estis modifita permane kompare kun la defaŭlta Debian.",
|
||||||
"diagnosis_regenconf_manually_modified_debian_details": "Ĉi tio probable estas bona, sed devas observi ĝin...",
|
"diagnosis_regenconf_manually_modified_debian_details": "Ĉi tio probable estas bona, sed devas observi ĝin...",
|
||||||
|
@ -541,12 +541,12 @@
|
||||||
"diagnosis_no_cache": "Neniu diagnoza kaŝmemoro por kategorio '{category}'",
|
"diagnosis_no_cache": "Neniu diagnoza kaŝmemoro por kategorio '{category}'",
|
||||||
"diagnosis_ip_broken_dnsresolution": "Rezolucio pri domajna nomo rompiĝas pro iu kialo ... Ĉu fajroŝirmilo blokas DNS-petojn ?",
|
"diagnosis_ip_broken_dnsresolution": "Rezolucio pri domajna nomo rompiĝas pro iu kialo ... Ĉu fajroŝirmilo blokas DNS-petojn ?",
|
||||||
"diagnosis_ip_broken_resolvconf": "Rezolucio pri domajna nomo ŝajnas esti rompita en via servilo, kiu ŝajnas rilata al /etc/resolv.conf ne notante 127.0.0.1.",
|
"diagnosis_ip_broken_resolvconf": "Rezolucio pri domajna nomo ŝajnas esti rompita en via servilo, kiu ŝajnas rilata al /etc/resolv.conf ne notante 127.0.0.1.",
|
||||||
"diagnosis_dns_missing_record": "Laŭ la rekomendita DNS-agordo, vi devas aldoni DNS-registron kun tipo {0}, nomo {1} kaj valoro {2}. Vi povas kontroli https://yunohost.org/dns_config por pliaj informoj.",
|
"diagnosis_dns_missing_record": "Laŭ la rekomendita DNS-agordo, vi devas aldoni DNS-registron kun\ntipo: {type}\nnomo: {name}\nvaloro: {value}",
|
||||||
"diagnosis_dns_discrepancy": "La DNS-registro kun tipo {0} kaj nomo {1} ne kongruas kun la rekomendita agordo. Nuna valoro: {2}. Esceptita valoro: {3}. Vi povas kontroli https://yunohost.org/dns_config por pliaj informoj.",
|
"diagnosis_dns_discrepancy": "La DNS-registro kun tipo {type} kaj nomo {name} ne kongruas kun la rekomendita agordo.\nNuna valoro: {current}\nEsceptita valoro: {value}",
|
||||||
"diagnosis_services_conf_broken": "Agordo estas rompita por servo {service} !",
|
"diagnosis_services_conf_broken": "Agordo estas rompita por servo {service} !",
|
||||||
"diagnosis_services_bad_status": "Servo {service} estas {status} :(",
|
"diagnosis_services_bad_status": "Servo {service} estas {status} :(",
|
||||||
"diagnosis_ram_low": "La sistemo havas {available_abs_MB} MB ({available_percent}%) RAM forlasita de {total_abs_MB} MB. Estu zorgema.",
|
"diagnosis_ram_low": "La sistemo havas {available} ({available_percent}%) RAM forlasita de {total}. Estu zorgema.",
|
||||||
"diagnosis_swap_ok": "La sistemo havas {total_MB} MB da interŝanĝoj!",
|
"diagnosis_swap_ok": "La sistemo havas {total} da interŝanĝoj!",
|
||||||
"diagnosis_mail_ougoing_port_25_ok": "Eliranta haveno 25 ne estas blokita kaj retpoŝto povas esti sendita al aliaj serviloj.",
|
"diagnosis_mail_ougoing_port_25_ok": "Eliranta haveno 25 ne estas blokita kaj retpoŝto povas esti sendita al aliaj serviloj.",
|
||||||
"diagnosis_regenconf_allgood": "Ĉiuj agordaj dosieroj kongruas kun la rekomendita agordo!",
|
"diagnosis_regenconf_allgood": "Ĉiuj agordaj dosieroj kongruas kun la rekomendita agordo!",
|
||||||
"diagnosis_regenconf_manually_modified": "Agordodosiero {file} estis permane modifita.",
|
"diagnosis_regenconf_manually_modified": "Agordodosiero {file} estis permane modifita.",
|
||||||
|
@ -555,8 +555,9 @@
|
||||||
"diagnosis_description_services": "Servo kontrolas staton",
|
"diagnosis_description_services": "Servo kontrolas staton",
|
||||||
"diagnosis_description_systemresources": "Rimedaj sistemoj",
|
"diagnosis_description_systemresources": "Rimedaj sistemoj",
|
||||||
"diagnosis_description_security": "Sekurecaj kontroloj",
|
"diagnosis_description_security": "Sekurecaj kontroloj",
|
||||||
"diagnosis_ports_could_not_diagnose": "Ne povis diagnozi, ĉu haveblaj havenoj de ekstere. Eraro: {error}",
|
"diagnosis_ports_could_not_diagnose": "Ne povis diagnozi, ĉu haveblaj havenoj de ekstere.",
|
||||||
"diagnosis_services_bad_status_tip": "Vi povas provi rekomenci la servon, kaj se ĝi ne funkcias, trarigardu la servajn protokolojn uzante 'yunohost service log {0}' aŭ tra la sekcio 'Servoj' de la retadreso.",
|
"diagnosis_ports_could_not_diagnose_details": "Eraro: {error}",
|
||||||
|
"diagnosis_services_bad_status_tip": "Vi povas provi rekomenci la servon, kaj se ĝi ne funkcias, trarigardu la servajn protokolojn uzante 'yunohost service log {service}' aŭ tra la sekcio 'Servoj' de la retadreso.",
|
||||||
"diagnosis_security_vulnerable_to_meltdown_details": "Por ripari tion, vi devas ĝisdatigi vian sistemon kaj rekomenci por ŝarĝi la novan linux-kernon (aŭ kontaktu vian servilan provizanton se ĉi tio ne funkcias). Vidu https://meltdownattack.com/ por pliaj informoj.",
|
"diagnosis_security_vulnerable_to_meltdown_details": "Por ripari tion, vi devas ĝisdatigi vian sistemon kaj rekomenci por ŝarĝi la novan linux-kernon (aŭ kontaktu vian servilan provizanton se ĉi tio ne funkcias). Vidu https://meltdownattack.com/ por pliaj informoj.",
|
||||||
"diagnosis_description_basesystem": "Baza sistemo",
|
"diagnosis_description_basesystem": "Baza sistemo",
|
||||||
"diagnosis_description_regenconf": "Sistemaj agordoj",
|
"diagnosis_description_regenconf": "Sistemaj agordoj",
|
||||||
|
@ -564,21 +565,21 @@
|
||||||
"log_domain_main_domain": "Faru '{}' kiel ĉefa domajno",
|
"log_domain_main_domain": "Faru '{}' kiel ĉefa domajno",
|
||||||
"diagnosis_http_timeout": "Tempolimigita dum provado kontakti vian servilon de ekstere. Ĝi ŝajnas esti neatingebla. Vi devus kontroli, ke vi ĝuste redonas la havenon 80, ke nginx funkcias kaj ke fajroŝirmilo ne interbatalas.",
|
"diagnosis_http_timeout": "Tempolimigita dum provado kontakti vian servilon de ekstere. Ĝi ŝajnas esti neatingebla. Vi devus kontroli, ke vi ĝuste redonas la havenon 80, ke nginx funkcias kaj ke fajroŝirmilo ne interbatalas.",
|
||||||
"diagnosis_http_connection_error": "Rilata eraro: ne povis konektiĝi al la petita domajno, tre probable ĝi estas neatingebla.",
|
"diagnosis_http_connection_error": "Rilata eraro: ne povis konektiĝi al la petita domajno, tre probable ĝi estas neatingebla.",
|
||||||
"diagnosis_http_unknown_error": "Eraro okazis dum provado atingi vian domajnon, tre probable ĝi estas neatingebla.",
|
|
||||||
"migration_description_0013_futureproof_apps_catalog_system": "Migru al la nova katalogosistemo pri estontecaj programoj",
|
"migration_description_0013_futureproof_apps_catalog_system": "Migru al la nova katalogosistemo pri estontecaj programoj",
|
||||||
"diagnosis_ignored_issues": "(+ {nb_ignored} ignorataj aferoj))",
|
"diagnosis_ignored_issues": "(+ {nb_ignored} ignorataj aferoj))",
|
||||||
"diagnosis_found_errors": "Trovis {errors} signifa(j) afero(j) rilata al {category}!",
|
"diagnosis_found_errors": "Trovis {errors} signifa(j) afero(j) rilata al {category}!",
|
||||||
"diagnosis_found_errors_and_warnings": "Trovis {errors} signifaj problemo (j) (kaj {warnings} averto) rilataj al {category}!",
|
"diagnosis_found_errors_and_warnings": "Trovis {errors} signifaj problemo (j) (kaj {warnings} averto) rilataj al {category}!",
|
||||||
"diagnosis_diskusage_low": "Stokado {mountpoint} (sur aparato {device)) restas nur {free_abs_GB} GB ({free_percent}%) spaco. Estu zorgema.",
|
"diagnosis_diskusage_low": "Stokado {mountpoint} (sur aparato {device)) restas nur {free} ({free_percent}%) spaco. Estu zorgema.",
|
||||||
"diagnosis_diskusage_ok": "Stokado {mountpoint} (sur aparato {device) ankoraŭ restas {free_abs_GB} GB ({free_percent}%) spaco!",
|
"diagnosis_diskusage_ok": "Stokado {mountpoint} (sur aparato {device) ankoraŭ restas {free} ({free_percent}%) spaco!",
|
||||||
"global_settings_setting_pop3_enabled": "Ebligu la protokolon POP3 por la poŝta servilo",
|
"global_settings_setting_pop3_enabled": "Ebligu la protokolon POP3 por la poŝta servilo",
|
||||||
"diagnosis_unknown_categories": "La jenaj kategorioj estas nekonataj: {categories}",
|
"diagnosis_unknown_categories": "La jenaj kategorioj estas nekonataj: {categories}",
|
||||||
"diagnosis_services_running": "Servo {service} funkcias!",
|
"diagnosis_services_running": "Servo {service} funkcias!",
|
||||||
"diagnosis_ports_unreachable": "Haveno {port} ne atingeblas de ekstere.",
|
"diagnosis_ports_unreachable": "Haveno {port} ne atingeblas de ekstere.",
|
||||||
"diagnosis_ports_ok": "Haveno {port} atingeblas de ekstere.",
|
"diagnosis_ports_ok": "Haveno {port} atingeblas de ekstere.",
|
||||||
"diagnosis_ports_needed_by": "Eksponi ĉi tiun havenon necesas por servo {0}",
|
"diagnosis_ports_needed_by": "Eksponi ĉi tiun havenon necesas por servo {service}",
|
||||||
"diagnosis_ports_forwarding_tip": "Por solvi ĉi tiun problemon, plej probable vi devas agordi la plusendon de haveno en via interreta enkursigilo kiel priskribite en https://yunohost.org/isp_box_config",
|
"diagnosis_ports_forwarding_tip": "Por solvi ĉi tiun problemon, plej probable vi devas agordi la plusendon de haveno en via interreta enkursigilo kiel priskribite en https://yunohost.org/isp_box_config",
|
||||||
"diagnosis_http_could_not_diagnose": "Ne povis diagnozi, ĉu atingeblas domajno de ekstere. Eraro: {error}",
|
"diagnosis_http_could_not_diagnose": "Ne povis diagnozi, ĉu atingeblas domajno de ekstere.",
|
||||||
|
"diagnosis_http_could_not_diagnose_details": "Eraro: {error}",
|
||||||
"diagnosis_http_ok": "Domajno {domain} atingeblas de ekstere.",
|
"diagnosis_http_ok": "Domajno {domain} atingeblas de ekstere.",
|
||||||
"diagnosis_http_unreachable": "Domajno {domain} estas atingebla per HTTP de ekstere.",
|
"diagnosis_http_unreachable": "Domajno {domain} estas atingebla per HTTP de ekstere.",
|
||||||
"domain_cannot_remove_main_add_new_one": "Vi ne povas forigi '{domain:s}' ĉar ĝi estas la ĉefa domajno kaj via sola domajno, vi devas unue aldoni alian domajnon uzante ''yunohost domain add <another-domain.com>', tiam agordi kiel ĉefan domajnon uzante 'yunohost domain main-domain -n <another-domain.com>' kaj tiam vi povas forigi la domajnon' {domain:s} 'uzante' yunohost domain remove {domain:s} '.'",
|
"domain_cannot_remove_main_add_new_one": "Vi ne povas forigi '{domain:s}' ĉar ĝi estas la ĉefa domajno kaj via sola domajno, vi devas unue aldoni alian domajnon uzante ''yunohost domain add <another-domain.com>', tiam agordi kiel ĉefan domajnon uzante 'yunohost domain main-domain -n <another-domain.com>' kaj tiam vi povas forigi la domajnon' {domain:s} 'uzante' yunohost domain remove {domain:s} '.'",
|
||||||
|
|
|
@ -505,7 +505,7 @@
|
||||||
"app_remove_after_failed_install": "Eliminando la aplicación tras el fallo de instalación…",
|
"app_remove_after_failed_install": "Eliminando la aplicación tras el fallo de instalación…",
|
||||||
"diagnosis_basesystem_host": "El servidor está ejecutando Debian {debian_version}.",
|
"diagnosis_basesystem_host": "El servidor está ejecutando Debian {debian_version}.",
|
||||||
"diagnosis_basesystem_kernel": "El servidor está ejecutando el núcleo de Linux {kernel_version}",
|
"diagnosis_basesystem_kernel": "El servidor está ejecutando el núcleo de Linux {kernel_version}",
|
||||||
"diagnosis_basesystem_ynh_single_version": "{0} versión: {1} ({2})",
|
"diagnosis_basesystem_ynh_single_version": "{package} versión: {version} ({repo})",
|
||||||
"diagnosis_basesystem_ynh_main_version": "El servidor está ejecutando YunoHost {main_version} ({repo})",
|
"diagnosis_basesystem_ynh_main_version": "El servidor está ejecutando YunoHost {main_version} ({repo})",
|
||||||
"diagnosis_basesystem_ynh_inconsistent_versions": "Está ejecutando versiones incoherentes de los paquetes de YunoHost... probablemente por una actualización errónea o parcial.",
|
"diagnosis_basesystem_ynh_inconsistent_versions": "Está ejecutando versiones incoherentes de los paquetes de YunoHost... probablemente por una actualización errónea o parcial.",
|
||||||
"diagnosis_failed_for_category": "Diagnóstico fallido para la categoría «{category}» : {error}",
|
"diagnosis_failed_for_category": "Diagnóstico fallido para la categoría «{category}» : {error}",
|
||||||
|
@ -528,9 +528,9 @@
|
||||||
"diagnosis_ip_no_ipv4": "El servidor no cuenta con ipv4 funcional.",
|
"diagnosis_ip_no_ipv4": "El servidor no cuenta con ipv4 funcional.",
|
||||||
"diagnosis_ip_not_connected_at_all": "¿¡Está conectado el servidor a internet!?",
|
"diagnosis_ip_not_connected_at_all": "¿¡Está conectado el servidor a internet!?",
|
||||||
"diagnosis_ip_broken_resolvconf": "DNS parece no funcionar en tu servidor, lo que parece estar relacionado con /etc/resolv.conf no apuntando a 127.0.0.1.",
|
"diagnosis_ip_broken_resolvconf": "DNS parece no funcionar en tu servidor, lo que parece estar relacionado con /etc/resolv.conf no apuntando a 127.0.0.1.",
|
||||||
"diagnosis_dns_missing_record": "Según la configuración DNS recomendada, deberías añadir un registro DNS de tipo {0}, nombre {1} y valor {2}. Puedes consultar https://yunohost.org/dns_config para más información.",
|
"diagnosis_dns_missing_record": "Según la configuración DNS recomendada, deberías añadir un registro DNS\ntipo: {type}\nnombre: {name}\nvalor: {value}",
|
||||||
"diagnosis_diskusage_low": "El almacenamiento {mountpoint} (en dispositivo {device}) solo tiene {free_abs_GB} GB ({free_percent}%) de espacio disponible. Ten cuidado.",
|
"diagnosis_diskusage_low": "El almacenamiento {mountpoint} (en dispositivo {device}) solo tiene {free} ({free_percent}%) de espacio disponible. Ten cuidado.",
|
||||||
"diagnosis_services_bad_status_tip": "Puedes intentar reiniciar el servicio, y si no funciona, echar un vistazo a los logs del servicio usando 'yunohost service log {0}' o a través de la sección 'Servicios' en webadmin.",
|
"diagnosis_services_bad_status_tip": "Puedes intentar reiniciar el servicio, y si no funciona, echar un vistazo a los logs del servicio usando 'yunohost service log {service}' o a través de la sección 'Servicios' en webadmin.",
|
||||||
"diagnosis_ip_connected_ipv6": "¡El servidor está conectado a internet a través de IPv6!",
|
"diagnosis_ip_connected_ipv6": "¡El servidor está conectado a internet a través de IPv6!",
|
||||||
"diagnosis_ip_no_ipv6": "El servidor no cuenta con IPv6 funcional.",
|
"diagnosis_ip_no_ipv6": "El servidor no cuenta con IPv6 funcional.",
|
||||||
"diagnosis_ip_dnsresolution_working": "¡DNS no está funcionando!",
|
"diagnosis_ip_dnsresolution_working": "¡DNS no está funcionando!",
|
||||||
|
@ -539,22 +539,22 @@
|
||||||
"diagnosis_ip_weird_resolvconf_details": "En su lugar, este fichero debería ser un enlace simbólico a /etc/resolvconf/run/resolv.conf apuntando a 127.0.0.1 (dnsmasq). Los servidores de nombre de domino deben configurarse a través de /etc/resolv.dnsmasq.conf.",
|
"diagnosis_ip_weird_resolvconf_details": "En su lugar, este fichero debería ser un enlace simbólico a /etc/resolvconf/run/resolv.conf apuntando a 127.0.0.1 (dnsmasq). Los servidores de nombre de domino deben configurarse a través de /etc/resolv.dnsmasq.conf.",
|
||||||
"diagnosis_dns_good_conf": "Buena configuración DNS para el dominio {domain} (categoría {category})",
|
"diagnosis_dns_good_conf": "Buena configuración DNS para el dominio {domain} (categoría {category})",
|
||||||
"diagnosis_dns_bad_conf": "Configuración mala o faltante de los DNS para el dominio {domain} (categoría {category})",
|
"diagnosis_dns_bad_conf": "Configuración mala o faltante de los DNS para el dominio {domain} (categoría {category})",
|
||||||
"diagnosis_dns_discrepancy": "El registro DNS con tipo {0} y nombre {1} no se corresponde a la configuración recomendada. Valor actual: {2}. Valor esperado: {3}. Puedes consultar https://yunohost.org/dns_config para más información.",
|
"diagnosis_dns_discrepancy": "El registro DNS con tipo {type} y nombre {name} no se corresponde a la configuración recomendada.\nValor actual: {current}\nValor esperado: {value}",
|
||||||
"diagnosis_services_bad_status": "El servicio {service} está {status} :(",
|
"diagnosis_services_bad_status": "El servicio {service} está {status} :(",
|
||||||
"diagnosis_diskusage_verylow": "El almacenamiento {mountpoint} (en el dispositivo {device}) sólo tiene {free_abs_GB} GB ({free_percent}%) de espacio disponible. Deberías considerar la posibilidad de limpiar algo de espacio.",
|
"diagnosis_diskusage_verylow": "El almacenamiento {mountpoint} (en el dispositivo {device}) sólo tiene {free} ({free_percent}%) de espacio disponible. Deberías considerar la posibilidad de limpiar algo de espacio.",
|
||||||
"diagnosis_diskusage_ok": "¡El almacenamiento {mountpoint} (en el dispositivo {device}) todavía tiene {free_abs_GB} GB ({free_percent}%) de espacio libre!",
|
"diagnosis_diskusage_ok": "¡El almacenamiento {mountpoint} (en el dispositivo {device}) todavía tiene {free} ({free_percent}%) de espacio libre!",
|
||||||
"diagnosis_services_conf_broken": "¡Mala configuración para el servicio {service}!",
|
"diagnosis_services_conf_broken": "¡Mala configuración para el servicio {service}!",
|
||||||
"diagnosis_services_running": "¡El servicio {service} está en ejecución!",
|
"diagnosis_services_running": "¡El servicio {service} está en ejecución!",
|
||||||
"diagnosis_failed": "No se ha podido obtener el resultado del diagnóstico para la categoría '{category}': {error}",
|
"diagnosis_failed": "No se ha podido obtener el resultado del diagnóstico para la categoría '{category}': {error}",
|
||||||
"diagnosis_ip_connected_ipv4": "¡El servidor está conectado a internet a través de IPv4!",
|
"diagnosis_ip_connected_ipv4": "¡El servidor está conectado a internet a través de IPv4!",
|
||||||
"diagnosis_security_vulnerable_to_meltdown_details": "Para corregir esto, debieras actualizar y reiniciar tu sistema para cargar el nuevo kernel de Linux (o contacta tu proveedor si esto no funciona). Mas información en https://meltdownattack.com/",
|
"diagnosis_security_vulnerable_to_meltdown_details": "Para corregir esto, debieras actualizar y reiniciar tu sistema para cargar el nuevo kernel de Linux (o contacta tu proveedor si esto no funciona). Mas información en https://meltdownattack.com/",
|
||||||
"diagnosis_ram_verylow": "Al sistema le queda solamente {available_abs_MB} MB ({available_percent}%) de RAM! (De un total de {total_abs_MB} MB)",
|
"diagnosis_ram_verylow": "Al sistema le queda solamente {available} ({available_percent}%) de RAM! (De un total de {total})",
|
||||||
"diagnosis_ram_low": "Al sistema le queda {available_abs_MB} MB ({available_percent}%) de RAM de un total de {total_abs_MB} MB. Cuidado.",
|
"diagnosis_ram_low": "Al sistema le queda {available} ({available_percent}%) de RAM de un total de {total}. Cuidado.",
|
||||||
"diagnosis_ram_ok": "El sistema aun tiene {available_abs_MB} MB ({available_percent}%) de RAM de un total de {total_abs_MB} MB.",
|
"diagnosis_ram_ok": "El sistema aun tiene {available} ({available_percent}%) de RAM de un total de {total}.",
|
||||||
"diagnosis_swap_none": "El sistema no tiene mas espacio de intercambio. Considera agregar por lo menos 256 MB de espacio de intercambio para evitar que el sistema se quede sin memoria.",
|
"diagnosis_swap_none": "El sistema no tiene mas espacio de intercambio. Considera agregar por lo menos {recommended} de espacio de intercambio para evitar que el sistema se quede sin memoria.",
|
||||||
"diagnosis_swap_notsomuch": "Al sistema le queda solamente {total_MB} MB de espacio de intercambio. Considera agregar al menos 256 MB para evitar que el sistema se quede sin memoria.",
|
"diagnosis_swap_notsomuch": "Al sistema le queda solamente {total} de espacio de intercambio. Considera agregar al menos {recommended} para evitar que el sistema se quede sin memoria.",
|
||||||
"diagnosis_mail_ougoing_port_25_ok": "El puerto de salida 25 no esta bloqueado y los correos electrónicos pueden ser enviados a otros servidores.",
|
"diagnosis_mail_ougoing_port_25_ok": "El puerto de salida 25 no esta bloqueado y los correos electrónicos pueden ser enviados a otros servidores.",
|
||||||
"diagnosis_mail_ougoing_port_25_blocked": "El puerto de salida 25 parece estar bloqueado. Intenta desbloquearlo con el panel de configuración de tu proveedor de servicios de Internet (o proveedor de halbergue). Mientras tanto, el servidor no podrá enviar correos electrónicos a otros servidores.",
|
"diagnosis_mail_outgoing_port_25_blocked": "El puerto de salida 25 parece estar bloqueado. Intenta desbloquearlo con el panel de configuración de tu proveedor de servicios de Internet (o proveedor de halbergue). Mientras tanto, el servidor no podrá enviar correos electrónicos a otros servidores.",
|
||||||
"diagnosis_regenconf_allgood": "Todos los archivos de configuración están en linea con la configuración recomendada!",
|
"diagnosis_regenconf_allgood": "Todos los archivos de configuración están en linea con la configuración recomendada!",
|
||||||
"diagnosis_regenconf_manually_modified": "El archivo de configuración {file} fue modificado manualmente.",
|
"diagnosis_regenconf_manually_modified": "El archivo de configuración {file} fue modificado manualmente.",
|
||||||
"diagnosis_regenconf_manually_modified_details": "Esto este probablemente BIEN siempre y cuando sepas lo que estas haciendo ;) !",
|
"diagnosis_regenconf_manually_modified_details": "Esto este probablemente BIEN siempre y cuando sepas lo que estas haciendo ;) !",
|
||||||
|
@ -568,11 +568,12 @@
|
||||||
"diagnosis_description_services": "Comprobación del estado de los servicios",
|
"diagnosis_description_services": "Comprobación del estado de los servicios",
|
||||||
"diagnosis_description_ports": "Exposición de puertos",
|
"diagnosis_description_ports": "Exposición de puertos",
|
||||||
"diagnosis_description_systemresources": "Recursos del sistema",
|
"diagnosis_description_systemresources": "Recursos del sistema",
|
||||||
"diagnosis_swap_ok": "El sistema tiene {total_MB} MB de espacio de intercambio!",
|
"diagnosis_swap_ok": "El sistema tiene {total} de espacio de intercambio!",
|
||||||
"diagnosis_ports_needed_by": "La apertura de este puerto es requerida para la funcionalidad {1} (service {0})",
|
"diagnosis_ports_needed_by": "La apertura de este puerto es requerida para la funcionalidad {category} (service {service})",
|
||||||
"diagnosis_ports_ok": "El puerto {port} es accesible desde internet.",
|
"diagnosis_ports_ok": "El puerto {port} es accesible desde internet.",
|
||||||
"diagnosis_ports_unreachable": "El puerto {port} no es accesible desde internet.",
|
"diagnosis_ports_unreachable": "El puerto {port} no es accesible desde internet.",
|
||||||
"diagnosis_ports_could_not_diagnose": "No se puede comprobar si los puertos están accesibles desde el exterior. Error: {error}",
|
"diagnosis_ports_could_not_diagnose": "No se puede comprobar si los puertos están accesibles desde el exterior.",
|
||||||
|
"diagnosis_ports_could_not_diagnose_details": "Error: {error}",
|
||||||
"diagnosis_description_security": "Validación de seguridad",
|
"diagnosis_description_security": "Validación de seguridad",
|
||||||
"diagnosis_description_regenconf": "Configuraciones de sistema",
|
"diagnosis_description_regenconf": "Configuraciones de sistema",
|
||||||
"diagnosis_description_mail": "Correo electrónico",
|
"diagnosis_description_mail": "Correo electrónico",
|
||||||
|
@ -592,10 +593,10 @@
|
||||||
"diagnosis_unknown_categories": "Las siguientes categorías están desconocidas: {categories}",
|
"diagnosis_unknown_categories": "Las siguientes categorías están desconocidas: {categories}",
|
||||||
"diagnosis_http_unreachable": "El dominio {domain} esta fuera de alcance desde internet y a través de HTTP.",
|
"diagnosis_http_unreachable": "El dominio {domain} esta fuera de alcance desde internet y a través de HTTP.",
|
||||||
"diagnosis_http_bad_status_code": "El sistema de diagnostico no pudo comunicarse con su servidor. Puede ser otra maquina que contesto en lugar del servidor. Debería verificar en su firewall que el re-direccionamiento del puerto 80 esta correcto.",
|
"diagnosis_http_bad_status_code": "El sistema de diagnostico no pudo comunicarse con su servidor. Puede ser otra maquina que contesto en lugar del servidor. Debería verificar en su firewall que el re-direccionamiento del puerto 80 esta correcto.",
|
||||||
"diagnosis_http_unknown_error": "Hubo un error durante la búsqueda de su dominio, parece inalcanzable.",
|
|
||||||
"diagnosis_http_connection_error": "Error de conexión: Ne se pudo conectar al dominio solicitado,",
|
"diagnosis_http_connection_error": "Error de conexión: Ne se pudo conectar al dominio solicitado,",
|
||||||
"diagnosis_http_timeout": "El intento de contactar a su servidor desde internet corrió fuera de tiempo. Al parece esta incomunicado. Debería verificar que nginx corre en el puerto 80, y que la redireción del puerto 80 no interfiere con en el firewall.",
|
"diagnosis_http_timeout": "El intento de contactar a su servidor desde internet corrió fuera de tiempo. Al parece esta incomunicado. Debería verificar que nginx corre en el puerto 80, y que la redireción del puerto 80 no interfiere con en el firewall.",
|
||||||
"diagnosis_http_ok": "El Dominio {domain} es accesible desde internet a través de HTTP.",
|
"diagnosis_http_ok": "El Dominio {domain} es accesible desde internet a través de HTTP.",
|
||||||
"diagnosis_http_could_not_diagnose": "No se pudo verificar si el dominio es accesible desde internet. Error: {error}",
|
"diagnosis_http_could_not_diagnose": "No se pudo verificar si el dominio es accesible desde internet.",
|
||||||
|
"diagnosis_http_could_not_diagnose_details": "Error: {error}",
|
||||||
"diagnosis_ports_forwarding_tip": "Para solucionar este incidente, debería configurar el \"port forwading\" en su router como especificado en https://yunohost.org/isp_box_config"
|
"diagnosis_ports_forwarding_tip": "Para solucionar este incidente, debería configurar el \"port forwading\" en su router como especificado en https://yunohost.org/isp_box_config"
|
||||||
}
|
}
|
||||||
|
|
274
locales/fr.json
274
locales/fr.json
|
@ -17,9 +17,9 @@
|
||||||
"app_removed": "{app:s} supprimé",
|
"app_removed": "{app:s} supprimé",
|
||||||
"app_requirements_checking": "Vérification des paquets requis pour {app} …",
|
"app_requirements_checking": "Vérification des paquets requis pour {app} …",
|
||||||
"app_requirements_unmeet": "Les pré-requis de {app} ne sont pas satisfaits, le paquet {pkgname} ({version}) doit être {spec}",
|
"app_requirements_unmeet": "Les pré-requis de {app} ne sont pas satisfaits, le paquet {pkgname} ({version}) doit être {spec}",
|
||||||
"app_sources_fetch_failed": "Impossible de récupérer les fichiers sources, l'URL est-elle correcte ?",
|
"app_sources_fetch_failed": "Impossible de récupérer les fichiers sources, l’URL est-elle correcte ?",
|
||||||
"app_unknown": "Application inconnue",
|
"app_unknown": "Application inconnue",
|
||||||
"app_unsupported_remote_type": "Ce type de commande à distance utilisé pour cette application n'est pas supporté",
|
"app_unsupported_remote_type": "Ce type de commande à distance utilisé pour cette application n’est pas supporté",
|
||||||
"app_upgrade_failed": "Impossible de mettre à jour {app:s} : {error}",
|
"app_upgrade_failed": "Impossible de mettre à jour {app:s} : {error}",
|
||||||
"app_upgraded": "{app:s} mis à jour",
|
"app_upgraded": "{app:s} mis à jour",
|
||||||
"ask_email": "Adresse de courriel",
|
"ask_email": "Adresse de courriel",
|
||||||
|
@ -35,14 +35,14 @@
|
||||||
"backup_archive_open_failed": "Impossible d’ouvrir l’archive de la sauvegarde",
|
"backup_archive_open_failed": "Impossible d’ouvrir l’archive de la 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_creation_failed": "Impossible de créer l'archive de la sauvegarde",
|
"backup_creation_failed": "Impossible de créer l’archive de la sauvegarde",
|
||||||
"backup_delete_error": "Impossible de supprimer '{path:s}'",
|
"backup_delete_error": "Impossible de supprimer '{path:s}'",
|
||||||
"backup_deleted": "La sauvegarde a été supprimée",
|
"backup_deleted": "La sauvegarde a été supprimée",
|
||||||
"backup_hook_unknown": "Script de sauvegarde '{hook:s}' inconnu",
|
"backup_hook_unknown": "Script de sauvegarde '{hook:s}' inconnu",
|
||||||
"backup_invalid_archive": "Archive de sauvegarde invalide",
|
"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 sous-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 répertoire de destination n'est pas vide",
|
"backup_output_directory_not_empty": "Le répertoire de destination n’est pas vide",
|
||||||
"backup_output_directory_required": "Vous devez spécifier un dossier de destination pour la sauvegarde",
|
"backup_output_directory_required": "Vous devez spécifier un dossier de destination pour la sauvegarde",
|
||||||
"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 personnalisée {app:s}",
|
"custom_app_url_required": "Vous devez spécifier une URL pour mettre à jour votre application personnalisée {app:s}",
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
"dyndns_cron_removed": "La tâche cron pour le domaine DynDNS enlevée",
|
"dyndns_cron_removed": "La tâche cron pour le domaine DynDNS enlevée",
|
||||||
"dyndns_ip_update_failed": "Impossible de mettre à jour l’adresse IP sur le domaine DynDNS",
|
"dyndns_ip_update_failed": "Impossible de mettre à jour l’adresse IP sur le domaine DynDNS",
|
||||||
"dyndns_ip_updated": "Mise à jour de votre IP pour le domaine DynDNS",
|
"dyndns_ip_updated": "Mise à jour de votre IP pour le domaine DynDNS",
|
||||||
"dyndns_key_generating": "Génération de la clé DNS ... , cela peut prendre un certain temps.",
|
"dyndns_key_generating": "Génération de la clé DNS …, cela peut prendre un certain temps.",
|
||||||
"dyndns_key_not_found": "Clé DNS introuvable pour le domaine",
|
"dyndns_key_not_found": "Clé DNS introuvable pour le domaine",
|
||||||
"dyndns_no_domain_registered": "Aucun domaine enregistré avec DynDNS",
|
"dyndns_no_domain_registered": "Aucun domaine enregistré avec DynDNS",
|
||||||
"dyndns_registered": "Domaine DynDNS enregistré",
|
"dyndns_registered": "Domaine DynDNS enregistré",
|
||||||
|
@ -75,18 +75,18 @@
|
||||||
"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": "Pare-feu rechargé",
|
"firewall_reloaded": "Pare-feu rechargé",
|
||||||
"firewall_rules_cmd_failed": "Certaines règles du pare-feu n’ont pas pu être appliquées. Plus d'info dans le journal de log.",
|
"firewall_rules_cmd_failed": "Certaines règles du pare-feu n’ont pas pu être appliquées. Plus d’info dans le journal de log.",
|
||||||
"hook_exec_failed": "Échec de l’exécution du script : {path:s}",
|
"hook_exec_failed": "Échec de l’exécution du script : {path:s}",
|
||||||
"hook_exec_not_terminated": "L’exécution du script {path:s} ne s’est pas terminée correctement",
|
"hook_exec_not_terminated": "L’exécution du script {path:s} ne s’est pas terminée correctement",
|
||||||
"hook_list_by_invalid": "Propriété invalide pour lister les actions par celle-ci",
|
"hook_list_by_invalid": "Propriété invalide pour lister les actions par celle-ci",
|
||||||
"hook_name_unknown": "Nom de l'action '{name:s}' inconnu",
|
"hook_name_unknown": "Nom de l’action '{name:s}' inconnu",
|
||||||
"installation_complete": "Installation terminée",
|
"installation_complete": "Installation terminée",
|
||||||
"installation_failed": "Quelque chose s'est mal passé lors de l'installation",
|
"installation_failed": "Quelque chose s’est mal passé lors de l’installation",
|
||||||
"ip6tables_unavailable": "Vous ne pouvez pas jouer avec ip6tables ici. Vous êtes soit dans un conteneur, soit votre noyau ne le prend pas en charge",
|
"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 initialisé",
|
"ldap_initialized": "L’annuaire LDAP initialisé",
|
||||||
"mail_alias_remove_failed": "Impossible de supprimer l’alias de courriel '{mail:s}'",
|
"mail_alias_remove_failed": "Impossible de supprimer l’alias de courriel '{mail:s}'",
|
||||||
"mail_domain_unknown": "Le domaine '{domain:s}' de cette adress de courriel n'est pas valide. Merci d'utiliser un domain administré par ce serveur.",
|
"mail_domain_unknown": "Le domaine '{domain:s}' de cette adresse de courriel n’est pas valide. Merci d’utiliser un domaine administré par ce serveur.",
|
||||||
"mail_forward_remove_failed": "Impossible de supprimer le courriel de transfert '{mail:s}'",
|
"mail_forward_remove_failed": "Impossible de supprimer le courriel de transfert '{mail:s}'",
|
||||||
"main_domain_change_failed": "Impossible de modifier le domaine principal",
|
"main_domain_change_failed": "Impossible de modifier le domaine principal",
|
||||||
"main_domain_changed": "Le domaine principal modifié",
|
"main_domain_changed": "Le domaine principal modifié",
|
||||||
|
@ -112,13 +112,13 @@
|
||||||
"restore_complete": "Restauré",
|
"restore_complete": "Restauré",
|
||||||
"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 ne l'est pas non plus dans l’archive",
|
"restore_hook_unavailable": "Le script de restauration '{part:s}' n’est pas disponible sur votre système, et ne l’est pas non plus dans l’archive",
|
||||||
"restore_nothings_done": "Rien n’a été restauré",
|
"restore_nothings_done": "Rien n’a été restauré",
|
||||||
"restore_running_app_script": "Exécution du script de restauration de l'application '{app:s}' .…",
|
"restore_running_app_script": "Exécution du script de restauration de l’application '{app:s}' …",
|
||||||
"restore_running_hooks": "Exécution des scripts de restauration …",
|
"restore_running_hooks": "Exécution des scripts de restauration …",
|
||||||
"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à en cours d'exécution",
|
"service_already_started": "Le service '{service:s}' est déjà en cours d’exécution",
|
||||||
"service_already_stopped": "Le service '{service:s}' est déjà arrêté",
|
"service_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_disable_failed": "Impossible de ne pas lancer le service « {service:s} » au démarrage.\n\nJournaux récents du service : {logs:s}",
|
"service_disable_failed": "Impossible de ne pas lancer le service « {service:s} » au démarrage.\n\nJournaux récents du service : {logs:s}",
|
||||||
|
@ -152,46 +152,46 @@
|
||||||
"user_deleted": "L’utilisateur supprimé",
|
"user_deleted": "L’utilisateur supprimé",
|
||||||
"user_deletion_failed": "Impossible de supprimer l’utilisateur {user}: {error}",
|
"user_deletion_failed": "Impossible de supprimer l’utilisateur {user}: {error}",
|
||||||
"user_home_creation_failed": "Impossible de créer le dossier personnel de l’utilisateur",
|
"user_home_creation_failed": "Impossible de créer le dossier personnel de l’utilisateur",
|
||||||
"user_unknown": "L'utilisateur {user:s} est inconnu",
|
"user_unknown": "L’utilisateur {user:s} est inconnu",
|
||||||
"user_update_failed": "Impossible de mettre à jour l'utilisateur {user}: {error}",
|
"user_update_failed": "Impossible de mettre à jour l’utilisateur {user}: {error}",
|
||||||
"user_updated": "L’utilisateur a été modifié",
|
"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 est maintenant configuré",
|
"yunohost_configured": "YunoHost est maintenant configuré",
|
||||||
"yunohost_installing": "L'installation de YunoHost est en cours …",
|
"yunohost_installing": "L’installation de YunoHost est en cours …",
|
||||||
"yunohost_not_installed": "YunoHost n'est pas correctement installé. Veuillez exécuter 'yunohost tools postinstall'",
|
"yunohost_not_installed": "YunoHost n’est pas correctement installé. Veuillez exécuter 'yunohost tools postinstall'",
|
||||||
"certmanager_attempt_to_replace_valid_cert": "Vous êtes en train de vouloir remplacer un certificat correct et valide pour le domaine {domain:s} ! (Utilisez --force pour contourner cela)",
|
"certmanager_attempt_to_replace_valid_cert": "Vous êtes en train de vouloir remplacer un certificat correct et valide pour le domaine {domain:s} ! (Utilisez --force pour contourner cela)",
|
||||||
"certmanager_domain_unknown": "Domaine {domain:s} inconnu",
|
"certmanager_domain_unknown": "Domaine {domain:s} inconnu",
|
||||||
"certmanager_domain_cert_not_selfsigned": "Le certificat du domaine {domain:s} n’est pas auto-signé. Voulez-vous vraiment le remplacer ? (Utilisez --force pour cela)",
|
"certmanager_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 émis 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} n'est pas sur le point d’expirer ! (Vous pouvez utiliser --force si vous savez ce que vous faites)",
|
"certmanager_attempt_to_renew_valid_cert": "Le certificat pour le domaine {domain:s} n’est pas sur le point d’expirer ! (Vous pouvez utiliser --force si vous savez ce que vous faites)",
|
||||||
"certmanager_domain_http_not_working": "Il semble que le domaine {domain:s} ne soit pas accessible via HTTP. Veuillez vérifier que vos configuration DNS et Nginx sont correctes",
|
"certmanager_domain_http_not_working": "Il semble que le domaine {domain:s} ne soit pas accessible via HTTP. Veuillez vérifier que vos configuration DNS et Nginx sont correctes",
|
||||||
"certmanager_error_no_A_record": "Aucun enregistrement DNS 'A' n’a été trouvé pour {domain:s}. Vous devez faire pointer votre nom de domaine vers votre machine pour être en mesure d’installer un certificat Let’s Encrypt ! (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)",
|
"certmanager_error_no_A_record": "Aucun enregistrement DNS 'A' n’a été trouvé pour {domain:s}. Vous devez faire pointer votre nom de domaine vers votre machine pour être en mesure d’installer un certificat Let’s Encrypt ! (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)",
|
||||||
"certmanager_domain_dns_ip_differs_from_public_ip": "L’enregistrement DNS 'A' du domaine {domain:s} est différent de l’adresse IP de ce serveur. Si vous avez récemment modifié votre enregistrement 'A', veuillez attendre sa propagation (quelques vérificateur de propagation DNS sont disponibles en ligne). (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)",
|
"certmanager_domain_dns_ip_differs_from_public_ip": "L’enregistrement DNS 'A' du domaine {domain:s} est différent de l’adresse IP de ce serveur. Si vous avez récemment modifié votre enregistrement 'A', veuillez attendre sa propagation (quelques vérificateurs de propagation DNS sont disponibles en ligne). (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)",
|
||||||
"certmanager_cannot_read_cert": "Quelque chose s’est mal passé lors de la tentative d’ouverture du certificat actuel pour le domaine {domain:s} (fichier : {file:s}), la cause est : {reason:s}",
|
"certmanager_cannot_read_cert": "Quelque chose s’est mal passé lors de la tentative d’ouverture du certificat actuel pour le domaine {domain:s} (fichier : {file:s}), la cause est : {reason:s}",
|
||||||
"certmanager_cert_install_success_selfsigned": "Le certificat auto-signé est maintenant installé pour le domaine « {domain:s} »",
|
"certmanager_cert_install_success_selfsigned": "Le certificat auto-signé est maintenant installé pour le domaine « {domain:s} »",
|
||||||
"certmanager_cert_install_success": "Le certificat Let’s Encrypt est maintenant installé pour le domaine « {domain:s} »",
|
"certmanager_cert_install_success": "Le certificat Let’s Encrypt est maintenant installé pour le domaine « {domain:s} »",
|
||||||
"certmanager_cert_renew_success": "Certificat Let's Encrypt renouvelé pour le domaine '{domain:s}'",
|
"certmanager_cert_renew_success": "Certificat Let’s Encrypt renouvelé pour le domaine '{domain:s}'",
|
||||||
"certmanager_cert_signing_failed": "Impossible de signer le nouveau certificat",
|
"certmanager_cert_signing_failed": "Impossible de signer le nouveau certificat",
|
||||||
"certmanager_no_cert_file": "Impossible de lire le fichier du certificat pour le domaine {domain:s} (fichier : {file:s})",
|
"certmanager_no_cert_file": "Impossible de lire le fichier du certificat pour le domaine {domain:s} (fichier : {file:s})",
|
||||||
"certmanager_conflicting_nginx_file": "Impossible de préparer le domaine pour le défi ACME : le fichier de configuration NGINX {filepath:s} est en conflit et doit être préalablement retiré",
|
"certmanager_conflicting_nginx_file": "Impossible de préparer le domaine pour le défi ACME : le fichier de configuration NGINX {filepath:s} est en conflit et doit être préalablement retiré",
|
||||||
"certmanager_hit_rate_limit": "Trop de certificats ont déjà été émis récemment pour ce même ensemble de domaines {domain:s}. Veuillez réessayer plus tard. Lisez https://letsencrypt.org/docs/rate-limits/ pour obtenir plus de détails sur les ratios et limitations",
|
"certmanager_hit_rate_limit": "Trop de certificats ont déjà été émis récemment pour ce même ensemble de domaines {domain:s}. Veuillez réessayer plus tard. Lisez https://letsencrypt.org/docs/rate-limits/ pour obtenir plus de détails sur les ratios et limitations",
|
||||||
"ldap_init_failed_to_create_admin": "L’initialisation de l'annuaire LDAP n’a pas réussi à créer l’utilisateur admin",
|
"ldap_init_failed_to_create_admin": "L’initialisation de l’annuaire LDAP n’a pas réussi à créer l’utilisateur admin",
|
||||||
"domain_cannot_remove_main": "Vous ne pouvez pas supprimer '{domain:s}' car il s'agit du domaine principal. Vous devez d'abord définir un autre domaine comme domaine principal à l'aide de 'yunohost domain main-domain -n <another-domain>', voici la liste des domaines candidats. : {other_domains:s}",
|
"domain_cannot_remove_main": "Vous ne pouvez pas supprimer '{domain:s}' car il s’agit du domaine principal. Vous devez d’abord définir un autre domaine comme domaine principal à l’aide de 'yunohost domain main-domain -n <another-domain>', voici la liste des domaines candidats. : {other_domains:s}",
|
||||||
"certmanager_self_ca_conf_file_not_found": "Le fichier de configuration pour l’autorité du certificat auto-signé est introuvable (fichier : {file:s})",
|
"certmanager_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 courriel 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 d'abord exécuter cert-install.",
|
"certmanager_acme_not_configured_for_domain": "Le certificat du domaine {domain:s} ne semble pas être correctement installé. Veuillez d’abord exécuter cert-install.",
|
||||||
"certmanager_http_check_timeout": "Expiration du délai lorsque le serveur a essayé de se contacter lui-même via HTTP en utilisant l'adresse IP public {ip:s} du domaine {domain:s}. Vous rencontrez peut-être un problème d’hairpinning ou alors le pare-feu/routeur en amont de votre serveur est mal configuré.",
|
"certmanager_http_check_timeout": "Expiration du délai lorsque le serveur a essayé de se contacter lui-même via HTTP en utilisant l’adresse IP public {ip:s} du domaine {domain:s}. Vous rencontrez peut-être un problème d’hairpinning ou alors le pare-feu/routeur en amont de votre serveur est mal configuré.",
|
||||||
"certmanager_couldnt_fetch_intermediate_cert": "Expiration du délai lors de la tentative de récupération du certificat intermédiaire depuis Let’s Encrypt. L’installation ou le renouvellement du certificat a été annulé. Veuillez réessayer plus tard.",
|
"certmanager_couldnt_fetch_intermediate_cert": "Expiration du délai lors de la tentative de récupération du certificat intermédiaire depuis Let’s Encrypt. L’installation ou le renouvellement du certificat a été annulé. Veuillez réessayer plus tard.",
|
||||||
"domain_hostname_failed": "Échec de l’utilisation d’un nouveau nom d’hôte. Cela pourrait causer des soucis plus tard (peut-être que ça n’en causera pas).",
|
"domain_hostname_failed": "Échec de l’utilisation d’un nouveau nom d’hôte. Cela pourrait causer des soucis plus tard (peut-être que ça n’en causera pas).",
|
||||||
"yunohost_ca_creation_success": "L’autorité de certification locale créée.",
|
"yunohost_ca_creation_success": "L’autorité de certification locale créée.",
|
||||||
"app_already_installed_cant_change_url": "Cette application est déjà installée. L’URL ne peut pas être changé simplement par cette fonction. Vérifiez si cela est disponible avec `app changeurl`.",
|
"app_already_installed_cant_change_url": "Cette application est déjà installée. L’URL ne peut pas être changé simplement par cette fonction. Vérifiez si cela est disponible avec `app changeurl`.",
|
||||||
"app_change_url_failed_nginx_reload": "Le redémarrage de Nginx a échoué. Voici la sortie de 'nginx -t' :\n{nginx_errors:s}",
|
"app_change_url_failed_nginx_reload": "Le redémarrage de Nginx a échoué. Voici la sortie de 'nginx -t' :\n{nginx_errors:s}",
|
||||||
"app_change_url_identical_domains": "L’ancien et le nouveau couple domaine/chemin_de_l'URL sont identiques pour ('{domain:s}{path:s}'), rien à faire.",
|
"app_change_url_identical_domains": "L’ancien et le nouveau couple domaine/chemin_de_l’URL sont identiques pour ('{domain:s}{path:s}'), rien à faire.",
|
||||||
"app_change_url_no_script": "L’application '{app_name:s}' ne prend pas encore en charge le changement d’URL. Vous devriez peut-être la mettre à jour.",
|
"app_change_url_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}",
|
||||||
|
@ -206,7 +206,7 @@
|
||||||
"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 celui-ci n'est pas pris en charge par le système.",
|
"global_settings_unknown_type": "Situation inattendue : la configuration {setting:s} semble avoir le type {unknown_type:s} mais celui-ci n’est pas pris en charge par le système.",
|
||||||
"global_settings_unknown_setting_from_settings_file": "Clé inconnue dans les paramètres : '{setting_key:s}', rejet de cette clé et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
|
"global_settings_unknown_setting_from_settings_file": "Clé inconnue dans les paramètres : '{setting_key:s}', rejet de cette clé et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
|
||||||
"backup_abstract_method": "Cette méthode de sauvegarde reste à implémenter",
|
"backup_abstract_method": "Cette méthode de sauvegarde reste à implémenter",
|
||||||
"backup_applying_method_tar": "Création de l’archive TAR de la sauvegarde …",
|
"backup_applying_method_tar": "Création de l’archive TAR de la sauvegarde …",
|
||||||
|
@ -214,8 +214,8 @@
|
||||||
"backup_applying_method_borg": "Envoi de tous les fichiers à sauvegarder dans le répertoire borg-backup …",
|
"backup_applying_method_borg": "Envoi de tous les fichiers à sauvegarder dans le répertoire borg-backup …",
|
||||||
"backup_applying_method_custom": "Appel de la méthode de sauvegarde personnalisée '{method:s}' …",
|
"backup_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_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_archive_writing_error": "Impossible d’ajouter des fichiers '{source:s}' (nommés dans l’archive : '{dest:s}') à sauvegarder dans l’archive compressée '{archive:s}'",
|
||||||
"backup_ask_for_copying_if_needed": "Voulez-vous effectuer la sauvegarde en utilisant {size:s} temporairement? (Cette méthode est utilisée car certains fichiers n'ont pas pu être préparés avec une méthode plus efficace.)",
|
"backup_ask_for_copying_if_needed": "Voulez-vous effectuer la sauvegarde en utilisant {size:s} temporairement ? (Cette méthode est utilisée car certains fichiers n’ont pas pu être préparés avec une méthode plus efficace.)",
|
||||||
"backup_borg_not_implemented": "La méthode de sauvegarde Borg n’est pas encore implémentée",
|
"backup_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} Mo pour organiser l’archive",
|
"backup_copying_to_organize_the_archive": "Copie de {size:s} Mo pour organiser l’archive",
|
||||||
|
@ -235,26 +235,26 @@
|
||||||
"global_settings_cant_serialize_settings": "Échec de la sérialisation des données de paramétrage car : {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_may_be_not_enough_disk_space": "Votre système semble ne pas avoir suffisamment d’espace disponible (L'espace libre est de {free_space:d} octets. Le besoin d'espace nécessaire est de {needed_space:d} octets. En appliquant une marge de sécurité, la quantité d'espace nécessaire est de {margin:d} octets)",
|
"restore_may_be_not_enough_disk_space": "Votre système semble ne pas avoir suffisamment d’espace disponible (L’espace libre est de {free_space:d} octets. Le besoin d’espace nécessaire est de {needed_space:d} octets. En appliquant une marge de sécurité, la quantité d’espace nécessaire est de {margin:d} octets)",
|
||||||
"restore_not_enough_disk_space": "Espace disponible insuffisant (L'espace libre est de {free_space:d} octets. Le besoin d'espace nécessaire est de {needed_space:d} octets. En appliquant une marge de sécurité, la quantité d'espace nécessaire est de {margin:d} octets)",
|
"restore_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 fournisseur/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.",
|
||||||
"migrations_cant_reach_migration_file": "Impossible d'accéder aux fichiers de migration via le chemin '%s'",
|
"migrations_cant_reach_migration_file": "Impossible d’accéder aux fichiers de migration via le chemin '%s'",
|
||||||
"migrations_loading_migration": "Chargement de la migration {id} …",
|
"migrations_loading_migration": "Chargement de la migration {id} …",
|
||||||
"migrations_migration_has_failed": "La migration {id} a échoué avec l’exception {exception} : annulation",
|
"migrations_migration_has_failed": "La migration {id} a échoué avec l’exception {exception} : annulation",
|
||||||
"migrations_no_migrations_to_run": "Aucune migration à lancer",
|
"migrations_no_migrations_to_run": "Aucune migration à lancer",
|
||||||
"migrations_skip_migration": "Ignorer et passer la migration {id} …",
|
"migrations_skip_migration": "Ignorer et passer la migration {id} …",
|
||||||
"server_shutdown": "Le serveur va éteindre",
|
"server_shutdown": "Le serveur va s’éteindre",
|
||||||
"server_shutdown_confirm": "Le serveur va être éteint immédiatement, 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": "Certaines applications n’ont pas été mises à jour",
|
"app_upgrade_some_app_failed": "Certaines applications n’ont pas été mises à jour",
|
||||||
"dyndns_could_not_check_provide": "Impossible de vérifier si {provider:s} peut fournir {domain:s}.",
|
"dyndns_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’application '{app}' par défaut pour le domaine '{domain}' car il est déjà utilisé par l'application '{other_app}'",
|
"app_make_default_location_already_used": "Impossible de configurer l’application '{app}' par défaut pour le domaine '{domain}' car il est déjà utilisé par l’application '{other_app}'",
|
||||||
"app_upgrade_app_name": "Mise à jour de l’application {app} …",
|
"app_upgrade_app_name": "Mise à jour de l’application {app} …",
|
||||||
"backup_output_symlink_dir_broken": "Votre répertoire d'archivage '{path:s}' est un lien symbolique brisé. Peut-être avez-vous oublié de re/monter ou de brancher le support de stockage sur lequel il pointe.",
|
"backup_output_symlink_dir_broken": "Votre répertoire d’archivage '{path:s}' est un lien symbolique brisé. Peut-être avez-vous oublié de re/monter ou de brancher le support de stockage sur lequel il pointe.",
|
||||||
"migrate_tsig_end": "La migration à HMAC-SHA-512 est terminée",
|
"migrate_tsig_end": "La migration à HMAC-SHA-512 est terminée",
|
||||||
"migrate_tsig_failed": "La migration du domaine DynDNS {domain} à hmac-sha512 a échoué. Annulation des modifications. Erreur : {error_code} - {error}",
|
"migrate_tsig_failed": "La migration du domaine DynDNS {domain} à hmac-sha512 a échoué. Annulation des modifications. Erreur : {error_code} - {error}",
|
||||||
"migrate_tsig_start": "L’algorithme de génération des clefs n’est pas suffisamment sécurisé pour la signature TSIG du domaine '{domain}', lancement de la migration vers HMAC-SHA-512 qui est plus sécurisé",
|
"migrate_tsig_start": "L’algorithme de génération des clefs n’est pas suffisamment sécurisé pour la signature TSIG du domaine '{domain}', lancement de la migration vers HMAC-SHA-512 qui est plus sécurisé",
|
||||||
|
@ -270,13 +270,13 @@
|
||||||
"migration_0003_patching_sources_list": "Modification du fichier 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’abord le réinitialiser à son état initial. Le fichier précédent sera disponible en tant que {backup_dest}.",
|
||||||
"migration_0003_yunohost_upgrade": "Démarrage de la mise à niveau du paquet YunoHost. La migration se terminera, mais la mise à jour réelle aura lieu immédiatement après. Une fois cette opération terminée, vous pourriez avoir à vous reconnecter à l’administration via le panel web.",
|
"migration_0003_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 la migration à Stretch.",
|
||||||
"migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est mal passé pendant la mise à niveau principale : le système est toujours sur Debian Jessie !? Pour investiguer sur le problème, veuillez regarder les journaux {log}:s …",
|
"migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est mal passé pendant la mise à niveau principale : le système est toujours sur Debian Jessie !? Pour investiguer sur le problème, veuillez regarder les journaux {log}:s …",
|
||||||
"migration_0003_general_warning": "Veuillez noter que cette migration est une opération délicate. Si l’équipe YunoHost a fait de son mieux pour la relire et la tester, la migration pourrait tout de même casser des parties de votre système ou de vos applications.\n\nEn conséquence, nous vous recommandons :\n - de lancer une sauvegarde de vos données ou applications critiques. Plus d’informations sur https://yunohost.org/backup ;\n - d’être patient après avoir lancé la migration : selon votre connexion internet et matériel, cela pourrait prendre jusqu’à quelques heures pour que tout soit à niveau.\n\nEn outre, le port SMTP utilisé par les clients de messagerie externes comme (Thunderbird ou K9-Mail) a été changé de 465 (SSL/TLS) à 587 (STARTTLS). L’ancien port 465 sera automatiquement fermé et le nouveau port 587 sera ouvert dans le pare-feu. Vous et vos utilisateurs *devront* adapter la configuration de vos clients de messagerie en conséquence.",
|
"migration_0003_general_warning": "Veuillez noter que cette migration est une opération délicate. Si l’équipe YunoHost a fait de son mieux pour la relire et la tester, la migration pourrait tout de même casser des parties de votre système ou de vos applications.\n\nEn conséquence, nous vous recommandons :\n - de lancer une sauvegarde de vos données ou applications critiques. Plus d’informations sur https://yunohost.org/backup ;\n - d’être patient après avoir lancé la migration : selon votre connexion internet et matériel, cela pourrait prendre jusqu’à quelques heures pour que tout soit à niveau.\n\nEn outre, le port SMTP utilisé par les clients de messagerie externes comme (Thunderbird ou K9-Mail) a été changé de 465 (SSL/TLS) à 587 (STARTTLS). L’ancien port 465 sera automatiquement fermé et le nouveau port 587 sera ouvert dans le pare-feu. Vous et vos utilisateurs *devront* adapter la configuration de vos clients de messagerie en conséquence.",
|
||||||
"migration_0003_problematic_apps_warning": "Veuillez noter que les applications installées potentiellement problématiques suivantes ont été détectées. Il semble que celles-ci n'ont pas été installées à partir d'un catalogue d'applications, ou ne sont pas marquées comme \"fonctionnelle\". Par conséquent, il ne peut pas être garanti qu'ils fonctionneront toujours après la mise à niveau: {problematic_apps}",
|
"migration_0003_problematic_apps_warning": "Veuillez noter que les applications installées potentiellement problématiques suivantes ont été détectées. Il semble que celles-ci n’ont pas été installées à partir d’un catalogue d’applications, ou ne sont pas marquées comme \"fonctionnelle\". Par conséquent, il ne peut pas être garanti qu’ils fonctionneront toujours après la mise à niveau: {problematic_apps}",
|
||||||
"migration_0003_modified_files": "Veuillez noter que les fichiers suivants ont été détectés comme modifiés manuellement et pourraient être écrasés à la fin de la mise à niveau : {manually_modified_files}",
|
"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 {id} doit être lancée manuellement. Veuillez aller dans Outils > Migrations dans l’interface admin, ou lancer `yunohost tools migrations migrate`.",
|
"migrations_to_be_ran_manually": "La migration {id} doit être lancée manuellement. Veuillez aller dans Outils > Migrations dans l’interface admin, ou lancer `yunohost tools migrations migrate`.",
|
||||||
|
@ -295,15 +295,15 @@
|
||||||
"service_description_slapd": "Stocke les utilisateurs, domaines et leurs informations liées",
|
"service_description_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 l'ouverture et la fermeture des ports de connexion aux services",
|
"service_description_yunohost-firewall": "Gère l’ouverture et la fermeture des ports de connexion aux services",
|
||||||
"experimental_feature": "Attention : cette fonctionnalité est expérimentale et ne doit pas être considérée comme stable, vous ne devriez pas l’utiliser à moins que vous ne sachiez ce que vous faites.",
|
"experimental_feature": "Attention : cette fonctionnalité est expérimentale et ne doit pas être considérée comme stable, vous ne devriez pas l’utiliser à moins que vous ne sachiez ce que vous faites.",
|
||||||
"log_corrupted_md_file": "Le fichier YAML de métadonnées associé aux logs est corrompu : '{md_file}'\nErreur : {error}",
|
"log_corrupted_md_file": "Le fichier YAML de métadonnées associé aux logs est corrompu : '{md_file}'\nErreur : {error}",
|
||||||
"log_category_404": "Le journal de la catégorie '{category}' n’existe pas",
|
"log_category_404": "Le journal de la catégorie '{category}' n’existe pas",
|
||||||
"log_link_to_log": "Journal complet de cette opération : '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\"> {desc} </a>'",
|
"log_link_to_log": "Journal complet de cette opération : '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\"> {desc} </a>'",
|
||||||
"log_help_to_get_log": "Pour voir le journal de cette opération '{desc}', utilisez la commande 'yunohost log display {name}'",
|
"log_help_to_get_log": "Pour voir le journal de cette opération '{desc}', utilisez la commande 'yunohost log display {name}'",
|
||||||
"log_link_to_failed_log": "L’opération '{desc}' a échouée ! Pour obtenir de l’aide, merci de partager le journal de l'opération en <a href=\"#/tools/logs/{name}\">cliquant ici</a>",
|
"log_link_to_failed_log": "L’opération '{desc}' a échoué ! Pour obtenir de l’aide, merci de partager le journal de l’opération en <a href=\"#/tools/logs/{name}\">cliquant ici</a>",
|
||||||
"backup_php5_to_php7_migration_may_fail": "Impossible de convertir votre archive pour prendre en charge PHP 7, vous pourriez ne plus pouvoir restaurer vos applications PHP (cause : {error:s})",
|
"backup_php5_to_php7_migration_may_fail": "Impossible de convertir votre archive pour prendre en charge PHP 7, vous pourriez ne plus pouvoir restaurer vos applications PHP (cause : {error:s})",
|
||||||
"log_help_to_get_failed_log": "L’opération '{desc}' a échouée ! Pour obtenir de l’aide, merci de partager le journal de l'opération en utilisant la commande 'yunohost log display {name} --share'",
|
"log_help_to_get_failed_log": "L’opération '{desc}' a échoué ! Pour obtenir de l’aide, merci de partager le journal de l’opération en utilisant la commande 'yunohost log display {name} --share'",
|
||||||
"log_does_exists": "Il n’existe pas de journal de l’opération ayant pour nom '{log}', utiliser 'yunohost log list' pour voir tous les fichiers de journaux disponibles",
|
"log_does_exists": "Il n’existe pas de journal de l’opération ayant pour nom '{log}', utiliser 'yunohost log list' pour voir tous les fichiers de journaux disponibles",
|
||||||
"log_operation_unit_unclosed_properly": "L’opération ne s’est pas terminée correctement",
|
"log_operation_unit_unclosed_properly": "L’opération ne s’est pas terminée correctement",
|
||||||
"log_app_change_url": "Changer l’URL de l’application '{}'",
|
"log_app_change_url": "Changer l’URL de l’application '{}'",
|
||||||
|
@ -337,14 +337,14 @@
|
||||||
"migration_description_0005_postgresql_9p4_to_9p6": "Migration des bases de données de PostgreSQL 9.4 vers PostgreSQL 9.6",
|
"migration_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": "Laissez suffisamment d'espace disponible dans {path} pour exécuter la migration.",
|
"migration_0005_not_enough_space": "Laissez suffisamment d’espace disponible dans {path} pour exécuter la migration.",
|
||||||
"service_description_php7.0-fpm": "Exécute des applications écrites en PHP avec NGINX",
|
"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 secrète) 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 secrète) et/ou d’utiliser différents types de caractères tels que : majuscules, minuscules, chiffres et caractères spéciaux.",
|
"good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères - bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères tels que : majuscules, minuscules, chiffres et caractères spéciaux.",
|
||||||
"migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root",
|
"migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root",
|
||||||
"migration_0006_disclaimer": "YunoHost s'attend maintenant à ce que les mots de passe administrateur et racine soient synchronisés. Cette migration remplace votre mot de passe root par le mot de passe administrateur.",
|
"migration_0006_disclaimer": "YunoHost s’attend maintenant à ce que les mots de passe administrateur et racine soient synchronisés. Cette migration remplace votre mot de passe root par le mot de passe administrateur.",
|
||||||
"password_listed": "Ce mot de passe est l'un des mots de passe les plus utilisés dans le monde. Veuillez choisir quelque chose d'un peu plus singulier.",
|
"password_listed": "Ce mot de passe 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 majuscules et des 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 majuscules, des minuscules et des caractères 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",
|
||||||
|
@ -352,33 +352,33 @@
|
||||||
"root_password_desynchronized": "Le mot de passe administrateur a été changé, mais YunoHost n’a pas pu le propager au 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": "Annulation.",
|
"aborting": "Annulation.",
|
||||||
"app_not_upgraded": "L’application {failed_app} n’a pas été mise à jour et par conséquence les applications suivantes n’ont pas été mises à jour : {apps}",
|
"app_not_upgraded": "L’application {failed_app} n’a pas été mise à jour et par conséquence les applications suivantes n’ont pas été mises à jour : {apps}",
|
||||||
"app_start_install": "Installation de l'application {app} …",
|
"app_start_install": "Installation de l’application {app} …",
|
||||||
"app_start_remove": "Suppression de l'application {app} …",
|
"app_start_remove": "Suppression de l’application {app} …",
|
||||||
"app_start_backup": "Collecte des fichiers devant être sauvegardés pour l'application {app} …",
|
"app_start_backup": "Collecte des fichiers devant être sauvegardés pour l’application {app} …",
|
||||||
"app_start_restore": "Restauration de l'application {app} …",
|
"app_start_restore": "Restauration de l’application {app} …",
|
||||||
"app_upgrade_several_apps": "Les applications suivantes seront mises à jour : {apps}",
|
"app_upgrade_several_apps": "Les applications suivantes seront mises à jour : {apps}",
|
||||||
"ask_new_domain": "Nouveau domaine",
|
"ask_new_domain": "Nouveau domaine",
|
||||||
"ask_new_path": "Nouveau chemin",
|
"ask_new_path": "Nouveau chemin",
|
||||||
"backup_actually_backuping": "Création d'une archive de sauvegarde à partir des fichiers collectés …",
|
"backup_actually_backuping": "Création d’une archive de sauvegarde à partir des fichiers collectés …",
|
||||||
"backup_mount_archive_for_restore": "Préparation de l'archive pour restauration …",
|
"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_warning": "Avertissement : cette application peut fonctionner mais n’est pas bien intégrée dans YunoHost. Certaines fonctionnalités telles que l’authentification unique et la sauvegarde/restauration peuvent ne pas être disponibles. L’installer quand même ? [{answers:s}] ",
|
||||||
"confirm_app_install_danger": "DANGER! Cette application est connue pour être encore expérimentale (si elle ne fonctionne pas explicitement)! Vous ne devriez probablement PAS l'installer à moins de savoir ce que vous faites. AUCUN SUPPORT ne sera fourni si cette application ne fonctionne pas ou casse votre système ... Si vous êtes prêt à prendre ce risque de toute façon, tapez '{answers:s}'",
|
"confirm_app_install_danger": "DANGER ! Cette application est connue pour être encore expérimentale (si elle ne fonctionne pas explicitement) ! Vous ne devriez probablement PAS l’installer à moins de savoir ce que vous faites. AUCUN SUPPORT ne sera fourni si cette application ne fonctionne pas ou casse votre système … Si vous êtes prêt à prendre ce risque de toute façon, tapez '{answers:s}'",
|
||||||
"confirm_app_install_thirdparty": "DANGER! Cette application ne fait pas partie du catalogue d'applications de Yunohost. L'installation d'applications tierces peut compromettre l'intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l'installer à moins de savoir ce que vous faites. AUCUN SUPPORT ne sera fourni si cette application ne fonctionne pas ou casse votre système ... Si vous êtes prêt à prendre ce risque de toute façon, tapez '{answers:s}'",
|
"confirm_app_install_thirdparty": "DANGER ! Cette application ne fait pas partie du catalogue d’applications de YunoHost. L’installation d’applications tierces peut compromettre l’intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l’installer à moins de savoir ce que vous faites. AUCUN SUPPORT ne sera fourni si cette application ne fonctionne pas ou casse votre système … Si vous êtes prêt à prendre ce risque de toute façon, tapez '{answers:s}'",
|
||||||
"dpkg_is_broken": "Vous ne pouvez pas faire ça maintenant car dpkg/apt (le gestionnaire de paquets du système) semble avoir laissé des choses non configurées. Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a'.",
|
"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}.",
|
"dyndns_could_not_check_available": "Impossible de vérifier si {domain:s} est disponible chez {provider:s}.",
|
||||||
"file_does_not_exist": "Le fichier dont le chemin est {path:s} n'existe pas.",
|
"file_does_not_exist": "Le fichier dont le chemin est {path:s} n’existe pas.",
|
||||||
"global_settings_setting_security_password_admin_strength": "Qualité du mot de passe administrateur",
|
"global_settings_setting_security_password_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_security_password_user_strength": "Qualité du mot de passe de l’utilisateur",
|
||||||
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Autoriser l'utilisation de la clé hôte DSA (obsolète) pour la configuration du service SSH",
|
"global_settings_setting_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}",
|
"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_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_description_0008_ssh_conf_managed_by_yunohost_step2": "La configuration SSH sera gérée par YunoHost (étape 2, manuelle)",
|
||||||
"migration_0007_cancelled": "Impossible d'améliorer la gestion de votre configuration SSH.",
|
"migration_0007_cancelled": "Impossible d’améliorer la gestion de votre configuration SSH.",
|
||||||
"migration_0007_cannot_restart": "SSH ne peut pas être redémarré après avoir essayé d'annuler la migration numéro 6.",
|
"migration_0007_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_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_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_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_dsa": "- La clé DSA sera désactivée. Par conséquent, il se peut que vous ayez besoin d’invalider un avertissement effrayant de votre client SSH afin de revérifier l’empreinte de votre serveur ;",
|
||||||
"migration_0008_warning": "Si vous comprenez ces avertissements et souhaitez que YunoHost écrase votre configuration actuelle, exécutez la migration. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.",
|
"migration_0008_warning": "Si vous comprenez ces avertissements et souhaitez que YunoHost écrase votre configuration actuelle, exécutez la migration. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.",
|
||||||
"migration_0008_no_warning": "Remplacer votre configuration SSH devrait être sûr, bien que cela ne puisse être promis ! Exécutez la migration pour la remplacer. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.",
|
"migration_0008_no_warning": "Remplacer votre configuration SSH devrait être sûr, bien que cela ne puisse être promis ! Exécutez la migration pour la remplacer. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.",
|
||||||
"migrations_success": "Migration {number} {name} réussie !",
|
"migrations_success": "Migration {number} {name} réussie !",
|
||||||
|
@ -391,10 +391,10 @@
|
||||||
"service_reload_or_restart_failed": "Impossible de recharger ou de redémarrer le service '{service:s}'\n\nJournaux historisés récents de ce service : {logs:s}",
|
"service_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é",
|
"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`.",
|
"this_action_broke_dpkg": "Cette action a laissé des paquets non configurés par dpkg/apt (les gestionnaires de paquets système). Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a`.",
|
||||||
"app_action_cannot_be_ran_because_required_services_down": "Ces services requis doivent être en cours d'exécution pour exécuter cette action: {services}. Essayez de les redémarrer pour continuer (et éventuellement rechercher pourquoi ils sont en panne).",
|
"app_action_cannot_be_ran_because_required_services_down": "Ces services requis doivent être en cours d’exécution pour exécuter cette action: {services}. Essayez de les redémarrer pour continuer (et éventuellement rechercher pourquoi ils sont en panne).",
|
||||||
"admin_password_too_long": "Veuillez choisir un mot de passe de moins de 127 caractères",
|
"admin_password_too_long": "Veuillez choisir un mot de passe de moins de 127 caractères",
|
||||||
"log_regen_conf": "Régénérer les configurations du système '{}'",
|
"log_regen_conf": "Régénérer les configurations du système '{}'",
|
||||||
"migration_0009_not_needed": "Cette migration semble avoir déjà été jouée ? On l'ignore.",
|
"migration_0009_not_needed": "Cette migration semble avoir déjà été jouée ? On l’ignore.",
|
||||||
"regenconf_file_backed_up": "Le fichier de configuration '{conf}' a été sauvegardé sous '{backup}'",
|
"regenconf_file_backed_up": "Le fichier de configuration '{conf}' a été sauvegardé sous '{backup}'",
|
||||||
"regenconf_file_copy_failed": "Impossible de copier le nouveau fichier de configuration '{new}' vers '{conf}'",
|
"regenconf_file_copy_failed": "Impossible de copier le nouveau fichier de configuration '{new}' vers '{conf}'",
|
||||||
"regenconf_file_manually_modified": "Le fichier de configuration '{conf}' a été modifié manuellement et ne sera pas mis à jour",
|
"regenconf_file_manually_modified": "Le fichier de configuration '{conf}' a été modifié manuellement et ne sera pas mis à jour",
|
||||||
|
@ -404,12 +404,12 @@
|
||||||
"regenconf_file_updated": "Le fichier de configuration '{conf}' a été mis à jour",
|
"regenconf_file_updated": "Le fichier de configuration '{conf}' a été mis à jour",
|
||||||
"regenconf_now_managed_by_yunohost": "Le fichier de configuration '{conf}' est maintenant géré par YunoHost (catégorie {category}).",
|
"regenconf_now_managed_by_yunohost": "Le fichier de configuration '{conf}' est maintenant géré par YunoHost (catégorie {category}).",
|
||||||
"regenconf_up_to_date": "La configuration est déjà à jour pour la catégorie '{category}'",
|
"regenconf_up_to_date": "La configuration est déjà à jour pour la catégorie '{category}'",
|
||||||
"already_up_to_date": "Il n'y a rien à faire ! Tout est déjà à jour !",
|
"already_up_to_date": "Il n’y a rien à faire ! Tout est déjà à jour !",
|
||||||
"global_settings_setting_security_nginx_compatibility": "Compatibilité versus compromis sécuritaire pour le serveur web nginx. Affecte les cryptogrammes (et d'autres aspects liés à la sécurité)",
|
"global_settings_setting_security_nginx_compatibility": "Compatibilité versus compromis sécuritaire pour le serveur web nginx. Affecte les cryptogrammes (et d’autres aspects liés à la sécurité)",
|
||||||
"global_settings_setting_security_ssh_compatibility": "Compatibilité versus compromis sécuritaire pour le serveur SSH. Affecte les cryptogrammes (et d'autres aspects liés à la sécurité)",
|
"global_settings_setting_security_ssh_compatibility": "Compatibilité versus compromis sécuritaire pour le serveur SSH. Affecte les cryptogrammes (et d’autres aspects liés à la sécurité)",
|
||||||
"global_settings_setting_security_postfix_compatibility": "Compatibilité versus compromis sécuritaire pour le serveur Postfix. Affecte les cryptogrammes (et d'autres aspects liés à la sécurité)",
|
"global_settings_setting_security_postfix_compatibility": "Compatibilité versus compromis sécuritaire pour le serveur Postfix. Affecte les cryptogrammes (et d’autres aspects liés à la sécurité)",
|
||||||
"migration_description_0009_decouple_regenconf_from_services": "Dissocier le mécanisme « regen-conf » des services",
|
"migration_description_0009_decouple_regenconf_from_services": "Dissocier le mécanisme « regen-conf » des services",
|
||||||
"migration_description_0010_migrate_to_apps_json": "Supprimer les catalogues d'applications obsolètes afin d'utiliser la nouvelle liste unifiée 'apps.json' à la place (les anciens catalogues seront remplacés durant la migration 13)",
|
"migration_description_0010_migrate_to_apps_json": "Supprimer les catalogues d’applications obsolètes afin d’utiliser la nouvelle liste unifiée 'apps.json' à la place (les anciens catalogues seront remplacés durant la migration 13)",
|
||||||
"regenconf_file_kept_back": "Le fichier de configuration '{conf}' devait être supprimé par « regen-conf » (catégorie {category}) mais a été conservé.",
|
"regenconf_file_kept_back": "Le fichier de configuration '{conf}' devait être supprimé par « regen-conf » (catégorie {category}) mais a été conservé.",
|
||||||
"regenconf_updated": "La configuration a été mise à jour pour '{category}'",
|
"regenconf_updated": "La configuration a été mise à jour pour '{category}'",
|
||||||
"regenconf_would_be_updated": "La configuration aurait dû être mise à jour pour la catégorie '{category}'",
|
"regenconf_would_be_updated": "La configuration aurait dû être mise à jour pour la catégorie '{category}'",
|
||||||
|
@ -429,7 +429,7 @@
|
||||||
"tools_upgrade_special_packages_explanation": "La mise à jour spéciale va continuer en arrière-plan. Veuillez ne pas lancer d’autres actions sur votre serveur pendant environ 10 minutes (en fonction de la vitesse du matériel). Après cela, il vous faudra peut-être vous reconnecter à la webadmin. Le journal de mise à niveau sera disponible dans Outils → Journal (dans la webadmin) ou via \"yunohost log list\" (en ligne de commande).",
|
"tools_upgrade_special_packages_explanation": "La mise à jour spéciale va continuer en arrière-plan. Veuillez ne pas lancer d’autres actions sur votre serveur pendant environ 10 minutes (en fonction de la vitesse du matériel). Après cela, il vous faudra peut-être vous reconnecter à la webadmin. Le journal de mise à niveau sera disponible dans Outils → Journal (dans la webadmin) ou via \"yunohost log list\" (en ligne de commande).",
|
||||||
"update_apt_cache_failed": "Impossible de mettre à jour le cache APT (gestionnaire de paquets Debian). Voici un extrait du fichier sources.list qui pourrait vous aider à identifier les lignes problématiques :\n{sourceslist}",
|
"update_apt_cache_failed": "Impossible de mettre à jour le cache APT (gestionnaire de paquets Debian). Voici un extrait du fichier sources.list qui pourrait vous aider à identifier les lignes problématiques :\n{sourceslist}",
|
||||||
"update_apt_cache_warning": "Des erreurs se sont produites lors de la mise à jour du cache APT (gestionnaire de paquets Debian). Voici un extrait des lignes du fichier sources.list qui pourrait vous aider à identifier les lignes problématiques :\n{sourceslist}",
|
"update_apt_cache_warning": "Des erreurs se sont produites lors de la mise à jour du cache APT (gestionnaire de paquets Debian). Voici un extrait des lignes du fichier sources.list qui pourrait vous aider à identifier les lignes problématiques :\n{sourceslist}",
|
||||||
"backup_permission": "Permission de sauvegarde pour l'application {app:s}",
|
"backup_permission": "Permission de sauvegarde pour l’application {app:s}",
|
||||||
"group_created": "Le groupe '{group}' a été créé",
|
"group_created": "Le groupe '{group}' a été créé",
|
||||||
"group_deleted": "Suppression du groupe '{group}'",
|
"group_deleted": "Suppression du groupe '{group}'",
|
||||||
"group_unknown": "Le groupe {group:s} est inconnu",
|
"group_unknown": "Le groupe {group:s} est inconnu",
|
||||||
|
@ -439,23 +439,23 @@
|
||||||
"group_deletion_failed": "Échec de la suppression du groupe '{group}': {error}",
|
"group_deletion_failed": "Échec de la suppression du groupe '{group}': {error}",
|
||||||
"log_user_group_delete": "Supprimer le groupe '{}'",
|
"log_user_group_delete": "Supprimer le groupe '{}'",
|
||||||
"log_user_group_update": "Mettre à jour '{}' pour le groupe",
|
"log_user_group_update": "Mettre à jour '{}' pour le groupe",
|
||||||
"mailbox_disabled": "La boîte aux lettres est désactivée pour l'utilisateur {user:s}",
|
"mailbox_disabled": "La boîte aux lettres est désactivée pour l’utilisateur {user:s}",
|
||||||
"app_action_broke_system": "Cette action semble avoir cassé des services importants : {services}",
|
"app_action_broke_system": "Cette action semble avoir cassé des services importants : {services}",
|
||||||
"apps_already_up_to_date": "Toutes les applications sont déjà à jour",
|
"apps_already_up_to_date": "Toutes les applications sont déjà à jour",
|
||||||
"migration_0011_create_group": "Création d'un groupe pour chaque utilisateur…",
|
"migration_0011_create_group": "Création d’un groupe pour chaque utilisateur…",
|
||||||
"migration_0011_done": "Migration terminée. Vous êtes maintenant en mesure de gérer des groupes d'utilisateurs.",
|
"migration_0011_done": "Migration terminée. Vous êtes maintenant en mesure de gérer des groupes d’utilisateurs.",
|
||||||
"migrations_must_provide_explicit_targets": "Vous devez fournir des cibles explicites lorsque vous utilisez '--skip' ou '--force-rerun'",
|
"migrations_must_provide_explicit_targets": "Vous devez fournir des cibles explicites lorsque vous utilisez '--skip' ou '--force-rerun'",
|
||||||
"migrations_no_such_migration": "Il n'y a pas de migration appelée '{id}'",
|
"migrations_no_such_migration": "Il n’y a pas de migration appelée '{id}'",
|
||||||
"migrations_pending_cant_rerun": "Ces migrations étant toujours en attente, vous ne pouvez pas les exécuter à nouveau : {ids}",
|
"migrations_pending_cant_rerun": "Ces migrations étant toujours en attente, vous ne pouvez pas les exécuter à nouveau : {ids}",
|
||||||
"migration_description_0012_postgresql_password_to_md5_authentication": "Forcer l'authentification PostgreSQL à utiliser MD5 pour les connexions locales",
|
"migration_description_0012_postgresql_password_to_md5_authentication": "Forcer l’authentification PostgreSQL à utiliser MD5 pour les connexions locales",
|
||||||
"migrations_exclusive_options": "'auto', '--skip' et '--force-rerun' sont des options mutuellement exclusives.",
|
"migrations_exclusive_options": "'auto', '--skip' et '--force-rerun' sont des options mutuellement exclusives.",
|
||||||
"migrations_not_pending_cant_skip": "Ces migrations ne sont pas en attente et ne peuvent donc pas être ignorées: {ids}",
|
"migrations_not_pending_cant_skip": "Ces migrations ne sont pas en attente et ne peuvent donc pas être ignorées: {ids}",
|
||||||
"migration_0011_can_not_backup_before_migration": "La sauvegarde du système n'a pas pu être terminée avant l'échec de la migration. Erreur: {error:s}",
|
"migration_0011_can_not_backup_before_migration": "La sauvegarde du système n’a pas pu être terminée avant l’échec de la migration. Erreur: {error:s}",
|
||||||
"migration_0011_migrate_permission": "Migration des autorisations des paramètres des applications vers LDAP …",
|
"migration_0011_migrate_permission": "Migration des autorisations des paramètres des applications vers LDAP …",
|
||||||
"migration_0011_migration_failed_trying_to_rollback": "La migration a échouée… Tentative de restauration du système.",
|
"migration_0011_migration_failed_trying_to_rollback": "La migration a échoué… Tentative de restauration du système.",
|
||||||
"migration_0011_rollback_success": "Système restauré.",
|
"migration_0011_rollback_success": "Système restauré.",
|
||||||
"migration_0011_update_LDAP_database": "Mise à jour de la base de données LDAP…",
|
"migration_0011_update_LDAP_database": "Mise à jour de la base de données LDAP…",
|
||||||
"migration_0011_backup_before_migration": "Création d'une sauvegarde des paramètres de la base de données LDAP et des applications avant la migration.",
|
"migration_0011_backup_before_migration": "Création d’une sauvegarde des paramètres de la base de données LDAP et des applications avant la migration.",
|
||||||
"permission_not_found": "Autorisation '{permission:s}' introuvable",
|
"permission_not_found": "Autorisation '{permission:s}' introuvable",
|
||||||
"permission_update_failed": "Impossible de mettre à jour la permission '{permission}' : {error}",
|
"permission_update_failed": "Impossible de mettre à jour la permission '{permission}' : {error}",
|
||||||
"permission_updated": "Permission '{permission:s}' mise à jour",
|
"permission_updated": "Permission '{permission:s}' mise à jour",
|
||||||
|
@ -467,21 +467,21 @@
|
||||||
"migrations_failed_to_load_migration": "Impossible de charger la migration {id}: {error}",
|
"migrations_failed_to_load_migration": "Impossible de charger la migration {id}: {error}",
|
||||||
"migrations_running_forward": "Exécution de la migration {id} …",
|
"migrations_running_forward": "Exécution de la migration {id} …",
|
||||||
"migrations_success_forward": "Migration {id} terminée",
|
"migrations_success_forward": "Migration {id} terminée",
|
||||||
"operation_interrupted": "L'opération a été interrompue manuellement ?",
|
"operation_interrupted": "L’opération a été interrompue manuellement ?",
|
||||||
"permission_already_exist": "L'autorisation '{permission}' existe déjà",
|
"permission_already_exist": "L’autorisation '{permission}' existe déjà",
|
||||||
"permission_created": "Permission '{permission:s}' créée",
|
"permission_created": "Permission '{permission:s}' créée",
|
||||||
"permission_creation_failed": "Impossible de créer l'autorisation '{permission}': {error}",
|
"permission_creation_failed": "Impossible de créer l’autorisation '{permission}' : {error}",
|
||||||
"permission_deleted": "Permission '{permission:s}' supprimée",
|
"permission_deleted": "Permission '{permission:s}' supprimée",
|
||||||
"permission_deletion_failed": "Impossible de supprimer la permission '{permission}' : {error}",
|
"permission_deletion_failed": "Impossible de supprimer la permission '{permission}' : {error}",
|
||||||
"migration_description_0011_setup_group_permission": "Initialiser les groupes d'utilisateurs et autorisations pour les applications et les services",
|
"migration_description_0011_setup_group_permission": "Initialiser les groupes d’utilisateurs et autorisations pour les applications et les services",
|
||||||
"migration_0011_LDAP_update_failed": "Impossible de mettre à jour LDAP. Erreur: {error:s}",
|
"migration_0011_LDAP_update_failed": "Impossible de mettre à jour LDAP. Erreur: {error:s}",
|
||||||
"group_already_exist": "Le groupe {group} existe déjà",
|
"group_already_exist": "Le groupe {group} existe déjà",
|
||||||
"group_already_exist_on_system": "Le groupe {group} existe déjà dans les groupes système",
|
"group_already_exist_on_system": "Le groupe {group} existe déjà dans les groupes système",
|
||||||
"group_cannot_be_deleted": "Le groupe {group} ne peut pas être supprimé manuellement.",
|
"group_cannot_be_deleted": "Le groupe {group} ne peut pas être supprimé manuellement.",
|
||||||
"group_user_already_in_group": "L'utilisateur {user} est déjà dans le groupe {group}",
|
"group_user_already_in_group": "L’utilisateur {user} est déjà dans le groupe {group}",
|
||||||
"group_user_not_in_group": "L'utilisateur {user} n'est pas dans le groupe {group}",
|
"group_user_not_in_group": "L’utilisateur {user} n’est pas dans le groupe {group}",
|
||||||
"log_permission_create": "Créer permission '{}'",
|
"log_permission_create": "Créer permission '{}'",
|
||||||
"log_permission_delete": "supprimer permission '{}'",
|
"log_permission_delete": "Supprimer permission '{}'",
|
||||||
"log_user_group_create": "Créer '{}' groupe",
|
"log_user_group_create": "Créer '{}' groupe",
|
||||||
"log_user_permission_update": "Mise à jour des accès pour la permission '{}'",
|
"log_user_permission_update": "Mise à jour des accès pour la permission '{}'",
|
||||||
"log_user_permission_reset": "Réinitialiser la permission '{}'",
|
"log_user_permission_reset": "Réinitialiser la permission '{}'",
|
||||||
|
@ -496,64 +496,73 @@
|
||||||
"group_cannot_edit_primary_group": "Le groupe '{group}' ne peut pas être édité manuellement. C'est le groupe principal destiné à ne contenir qu'un utilisateur spécifique.",
|
"group_cannot_edit_primary_group": "Le groupe '{group}' ne peut pas être édité manuellement. C'est le groupe principal destiné à ne contenir qu'un utilisateur spécifique.",
|
||||||
"log_permission_url": "Mise à jour de l'URL associée à l'autorisation '{}'",
|
"log_permission_url": "Mise à jour de l'URL associée à l'autorisation '{}'",
|
||||||
"migration_0011_slapd_config_will_be_overwritten": "Il semble que vous ayez modifié manuellement la configuration de slapd. Pour cette migration critique, YunoHost doit forcer la mise à jour de la configuration de slapd. Les fichiers originaux seront sauvegardés dans {conf_backup_folder}.",
|
"migration_0011_slapd_config_will_be_overwritten": "Il semble que vous ayez modifié manuellement la configuration de slapd. Pour cette migration critique, YunoHost doit forcer la mise à jour de la configuration de slapd. Les fichiers originaux seront sauvegardés dans {conf_backup_folder}.",
|
||||||
"permission_already_up_to_date": "L'autorisation n'a pas été mise à jour car les demandes d'ajout/suppression correspondent déjà à l'état actuel.",
|
"permission_already_up_to_date": "L’autorisation n’a pas été mise à jour car les demandes d’ajout/suppression correspondent déjà à l’état actuel.",
|
||||||
"permission_currently_allowed_for_all_users": "Cette autorisation est actuellement accordée à tous les utilisateurs en plus des autres groupes. Vous voudrez probablement soit supprimer l'autorisation 'all_users', soit supprimer les autres groupes auxquels il est actuellement autorisé.",
|
"permission_currently_allowed_for_all_users": "Cette autorisation est actuellement accordée à tous les utilisateurs en plus des autres groupes. Vous voudrez probablement soit supprimer l’autorisation 'all_users', soit supprimer les autres groupes auxquels il est actuellement autorisé.",
|
||||||
"app_install_failed": "Impossible d'installer {app}: {error}",
|
"app_install_failed": "Impossible d’installer {app}: {error}",
|
||||||
"app_install_script_failed": "Une erreur est survenue dans le script d'installation de l'application",
|
"app_install_script_failed": "Une erreur est survenue dans le script d’installation de l’application",
|
||||||
"permission_require_account": "Permission {permission} n'a de sens que pour les utilisateurs ayant un compte et ne peut donc pas être activé pour les visiteurs.",
|
"permission_require_account": "Permission {permission} n’a de sens que pour les utilisateurs ayant un compte et ne peut donc pas être activé pour les visiteurs.",
|
||||||
"app_remove_after_failed_install": "Supprimer l'application après l'échec de l'installation…",
|
"app_remove_after_failed_install": "Supprimer l’application après l’échec de l’installation …",
|
||||||
"diagnosis_display_tip_web": "Vous pouvez aller à la section Diagnostic (dans l'écran d'accueil) pour voir les problèmes rencontrés.",
|
"diagnosis_display_tip_web": "Vous pouvez aller à la section Diagnostic (dans l’écran d’accueil) pour voir les problèmes rencontrés.",
|
||||||
"diagnosis_cant_run_because_of_dep": "Impossible d'exécuter le diagnostic pour {category} alors qu'il existe des problèmes importants liés à {dep}.",
|
"diagnosis_cant_run_because_of_dep": "Impossible d’exécuter le diagnostic pour {category} alors qu’il existe des problèmes importants liés à {dep}.",
|
||||||
"diagnosis_found_errors": "Trouvé {errors} problème(s) significatif(s) lié(s) à {category} !",
|
"diagnosis_found_errors": "Trouvé {errors} problème(s) significatif(s) lié(s) à {category} !",
|
||||||
"diagnosis_found_errors_and_warnings": "Trouvé {errors} problème(s) significatif(s) (et {warnings} (avertissement(s)) en relation avec {category} !",
|
"diagnosis_found_errors_and_warnings": "Trouvé {errors} problème(s) significatif(s) (et {warnings} (avertissement(s)) en relation avec {category} !",
|
||||||
"diagnosis_ip_not_connected_at_all": "Le serveur ne semble pas du tout connecté à Internet !?",
|
"diagnosis_ip_not_connected_at_all": "Le serveur ne semble pas du tout connecté à Internet !?",
|
||||||
"diagnosis_ip_weird_resolvconf": "La résolution DNS semble fonctionner, mais soyez prudent en utilisant un fichier /etc/resolv.conf personnalisé.",
|
"diagnosis_ip_weird_resolvconf": "La résolution DNS semble fonctionner, mais soyez prudent en utilisant un fichier /etc/resolv.conf personnalisé.",
|
||||||
"diagnosis_ip_weird_resolvconf_details": "Au lieu de cela, ce fichier devrait être un lien symbolique vers /etc/resolvconf/run/resolv.conf lui-même pointant vers 127.0.0.1 (dnsmasq). Les résolveurs réels doivent être configurés dans /etc/resolv.dnsmasq.conf.",
|
"diagnosis_ip_weird_resolvconf_details": "Au lieu de cela, ce fichier devrait être un lien symbolique vers /etc/resolvconf/run/resolv.conf lui-même pointant vers 127.0.0.1 (dnsmasq). Les résolveurs réels doivent être configurés dans /etc/resolv.dnsmasq.conf.",
|
||||||
"diagnosis_dns_missing_record": "Selon la configuration DNS recommandée, vous devez ajouter un enregistrement DNS de type {0}, nom {1} et valeur {2}. Vous pouvez consulter https://yunohost.org/dns_config pour plus d'informations.",
|
"diagnosis_dns_missing_record": "Selon la configuration DNS recommandée, vous devez ajouter un enregistrement DNS\nType: {type}\nNom: {name}\nValeur {value}",
|
||||||
"diagnosis_diskusage_ok": "Le stockage {mountpoint} (sur le périphérique {device}) a encore {free_abs_GB} Go ({free_percent}%) d'espace libre !",
|
"diagnosis_diskusage_ok": "Le stockage {mountpoint} (sur le périphérique {device}) a encore {free} ({free_percent}%) d’espace libre !",
|
||||||
"diagnosis_ram_ok": "Le système dispose encore de {available_abs_MB} MB ({available_percent}%) de RAM sur {total_abs_MB} MB.",
|
"diagnosis_ram_ok": "Le système dispose encore de {available} ({available_percent}%) de RAM sur {total}.",
|
||||||
"diagnosis_regenconf_allgood": "Tous les fichiers de configuration sont conformes à la configuration recommandée !",
|
"diagnosis_regenconf_allgood": "Tous les fichiers de configuration sont conformes à la configuration recommandée !",
|
||||||
"diagnosis_security_vulnerable_to_meltdown": "Vous semblez vulnérable à la vulnérabilité de sécurité critique de Meltdown",
|
"diagnosis_security_vulnerable_to_meltdown": "Vous semblez vulnérable à la vulnérabilité de sécurité critique de Meltdown",
|
||||||
"diagnosis_basesystem_host": "Le serveur utilise Debian {debian_version}",
|
"diagnosis_basesystem_host": "Le serveur utilise Debian {debian_version}",
|
||||||
"diagnosis_basesystem_kernel": "Le serveur utilise le noyau Linux {kernel_version}",
|
"diagnosis_basesystem_kernel": "Le serveur utilise le noyau Linux {kernel_version}",
|
||||||
"diagnosis_basesystem_ynh_single_version": "{0} version: {1} ({2})",
|
"diagnosis_basesystem_ynh_single_version": "{package} version: {version} ({repo})",
|
||||||
"diagnosis_basesystem_ynh_main_version": "Le serveur utilise YunoHost {main_version} ({repo})",
|
"diagnosis_basesystem_ynh_main_version": "Le serveur utilise YunoHost {main_version} ({repo})",
|
||||||
"diagnosis_basesystem_ynh_inconsistent_versions": "Vous exécutez des versions incohérentes des packages YunoHost ... probablement à cause d'une mise à niveau partielle ou échouée.",
|
"diagnosis_basesystem_ynh_inconsistent_versions": "Vous exécutez des versions incohérentes des packages YunoHost … probablement à cause d’une mise à niveau partielle ou échouée.",
|
||||||
"diagnosis_display_tip_cli": "Vous pouvez exécuter 'yunohost diagnosis show --issues' pour afficher les problèmes détectés.",
|
"diagnosis_display_tip_cli": "Vous pouvez exécuter 'yunohost diagnosis show --issues' pour afficher les problèmes détectés.",
|
||||||
"diagnosis_failed_for_category": "Échec du diagnostic pour la catégorie '{category}': {error}",
|
"diagnosis_failed_for_category": "Échec du diagnostic pour la catégorie '{category}': {error}",
|
||||||
"diagnosis_cache_still_valid": "(Le cache est toujours valide pour le diagnostic {category}. Pas re-diagnostiquer pour le moment!)",
|
"diagnosis_cache_still_valid": "(Le cache est encore valide pour le diagnostic {category}. Il ne sera pas re-diagnostiqué pour le moment!)",
|
||||||
"diagnosis_ignored_issues": "(+ {nb_ignored} questions ignorée(s))",
|
"diagnosis_ignored_issues": "(+ {nb_ignored} questions ignorée(s))",
|
||||||
"diagnosis_found_warnings": "Trouvé {warnings} objet(s) pouvant être amélioré(s) pour {category}.",
|
"diagnosis_found_warnings": "Trouvé {warnings} objet(s) pouvant être amélioré(s) pour {category}.",
|
||||||
"diagnosis_everything_ok": "Tout semble bien pour {category} !",
|
"diagnosis_everything_ok": "Tout semble bien pour {category} !",
|
||||||
"diagnosis_failed": "Impossible d'extraire le résultat du diagnostic pour la catégorie '{category}': {error}",
|
"diagnosis_failed": "Impossible d’extraire le résultat du diagnostic pour la catégorie '{category}': {error}",
|
||||||
"diagnosis_ip_connected_ipv4": "Le serveur est connecté à Internet en IPv4 !",
|
"diagnosis_ip_connected_ipv4": "Le serveur est connecté à Internet en IPv4 !",
|
||||||
"diagnosis_ip_no_ipv4": "Le serveur ne dispose pas d’une adresse IPv4.",
|
"diagnosis_ip_no_ipv4": "Le serveur ne dispose pas d’une adresse IPv4.",
|
||||||
"diagnosis_ip_connected_ipv6": "Le serveur est connecté à Internet en IPv6 !",
|
"diagnosis_ip_connected_ipv6": "Le serveur est connecté à Internet en IPv6 !",
|
||||||
"diagnosis_ip_no_ipv6": "Le serveur ne dispose pas d'une adresse IPv6.",
|
"diagnosis_ip_no_ipv6": "Le serveur ne dispose pas d’une adresse IPv6.",
|
||||||
"diagnosis_ip_dnsresolution_working": "La résolution de nom de domaine fonctionne !",
|
"diagnosis_ip_dnsresolution_working": "La résolution de nom de domaine fonctionne !",
|
||||||
"diagnosis_ip_broken_dnsresolution": "La résolution du nom de domaine semble interrompue pour une raison quelconque... Un pare-feu bloque-t-il les requêtes DNS ?",
|
"diagnosis_ip_broken_dnsresolution": "La résolution du nom de domaine semble interrompue pour une raison quelconque … Un pare-feu bloque-t-il les requêtes DNS ?",
|
||||||
"diagnosis_ip_broken_resolvconf": "La résolution du nom de domaine semble cassée sur votre serveur, ce qui semble lié au fait que /etc/resolv.conf ne pointe pas vers 127.0.0.1.",
|
"diagnosis_ip_broken_resolvconf": "La résolution du nom de domaine semble cassée sur votre serveur, ce qui semble lié au fait que /etc/resolv.conf ne pointe pas vers 127.0.0.1.",
|
||||||
"diagnosis_dns_good_conf": "Bonne configuration DNS pour le domaine {domain} (catégorie {category})",
|
"diagnosis_dns_good_conf": "Bonne configuration DNS pour le domaine {domain} (catégorie {category})",
|
||||||
"diagnosis_dns_bad_conf": "Configuration DNS incorrecte ou manquante pour le domaine {domain} (catégorie {category})",
|
"diagnosis_dns_bad_conf": "Configuration DNS incorrecte ou manquante pour le domaine {domain} (catégorie {category})",
|
||||||
"diagnosis_dns_discrepancy": "L'enregistrement DNS de type {0} et nom {1} ne correspond pas à la configuration recommandée. Valeur actuelle: {2}. Valeur exceptée: {3}. Vous pouvez consulter https://yunohost.org/dns_config pour plus d'informations.",
|
"diagnosis_dns_discrepancy": "L’enregistrement DNS de type {0} et nom {1} ne correspond pas à la configuration recommandée. Valeur actuelle: {2}. Valeur exceptée: {3}. Vous pouvez consulter https://yunohost.org/dns_config pour plus d’informations.",
|
||||||
"diagnosis_services_bad_status": "Le service {service} est {status} :-(",
|
"diagnosis_services_bad_status": "Le service {service} est {status} :-(",
|
||||||
"diagnosis_diskusage_verylow": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free_abs_GB} Go ({free_percent}%). Vous devriez vraiment envisager de nettoyer un peu d'espace.",
|
"diagnosis_diskusage_verylow": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free_abs_GB} Go ({free_percent}%). Vous devriez vraiment envisager de nettoyer un peu d’espace.",
|
||||||
"diagnosis_diskusage_low": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free_abs_GB} Go ({free_percent}%). Faites attention.",
|
"diagnosis_diskusage_low": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free_abs_GB} Go ({free_percent}%). Faites attention.",
|
||||||
"diagnosis_ram_verylow": "Le système ne dispose plus que de {available_abs_MB} MB ({available_percent}%) ! (sur {total_abs_MB} Mo)",
|
"diagnosis_ram_verylow": "Le système ne dispose plus que de {available_abs_MB} MB ({available_percent}%) ! (sur {total_abs_MB} Mo)",
|
||||||
"diagnosis_ram_low": "Le système n'a plus de {available_abs_MB} MB ({available_percent}%) RAM sur {total_abs_MB} MB. Faites attention.",
|
"diagnosis_ram_low": "Le système n’a plus de {available_abs_MB} MB ({available_percent}%) RAM sur {total_abs_MB} MB. Faites attention.",
|
||||||
"diagnosis_swap_none": "Le système n'a aucun échange. Vous devez envisager d’ajouter au moins 256 Mo de swap pour éviter les situations où le système manque de mémoire.",
|
"diagnosis_swap_none": "Le système n’a aucun échange. Vous devez envisager d’ajouter au moins 256 Mo de swap pour éviter les situations où le système manque de mémoire.",
|
||||||
"diagnosis_swap_notsomuch": "Le système ne dispose que de {total_MB} Mo de swap. Vous devez envisager d'avoir au moins 256 Mo pour éviter les situations où le système manque de mémoire.",
|
"diagnosis_swap_notsomuch": "Le système ne dispose que de {total_MB} Mo de swap. Vous devez envisager d’avoir au moins 256 Mo pour éviter les situations où le système manque de mémoire.",
|
||||||
"diagnosis_swap_ok": "Le système dispose de {total_MB} Mo de swap !",
|
"diagnosis_swap_ok": "Le système dispose de {total_MB} Mo de swap !",
|
||||||
|
"diagnosis_dns_discrepancy": "L’enregistrement DNS de type {type} et nom {name} ne correspond pas à la configuration recommandée.\nValeur actuelle: {current}\nValeur attendue: {value}",
|
||||||
|
"diagnosis_services_bad_status": "Le service {service} est {status} :-(",
|
||||||
|
"diagnosis_diskusage_verylow": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free} ({free_percent}%). Vous devriez vraiment envisager de nettoyer un peu d’espace.",
|
||||||
|
"diagnosis_diskusage_low": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free} ({free_percent}%). Faites attention.",
|
||||||
|
"diagnosis_ram_verylow": "Le système ne dispose plus que de {available} ({available_percent}%)! (sur {total})",
|
||||||
|
"diagnosis_ram_low": "Le système n’a plus de {available} ({available_percent}%) RAM sur {total}. Faites attention.",
|
||||||
|
"diagnosis_swap_none": "Le système n’a aucun espace de swap. Vous devriez envisager d’ajouter au moins {recommended} de swap pour éviter les situations où le système manque de mémoire.",
|
||||||
|
"diagnosis_swap_notsomuch": "Le système ne dispose que de {total} de swap. Vous devez envisager d’avoir au moins {recommended} pour éviter les situations où le système manque de mémoire.",
|
||||||
|
"diagnosis_swap_ok": "Le système dispose de {total} de swap !",
|
||||||
"diagnosis_regenconf_manually_modified": "Le fichier de configuration {file} a été modifié manuellement.",
|
"diagnosis_regenconf_manually_modified": "Le fichier de configuration {file} a été modifié manuellement.",
|
||||||
"diagnosis_regenconf_manually_modified_debian": "Le fichier de configuration {file} a été modifié manuellement par rapport à celui par défaut de Debian.",
|
"diagnosis_regenconf_manually_modified_debian": "Le fichier de configuration {file} a été modifié manuellement par rapport à celui par défaut de Debian.",
|
||||||
"diagnosis_regenconf_manually_modified_details": "C'est probablement OK tant que vous savez ce que vous faites;) !",
|
"diagnosis_regenconf_manually_modified_details": "C’est probablement OK tant que vous savez ce que vous faites ;) !",
|
||||||
"diagnosis_regenconf_manually_modified_debian_details": "Cela peut probablement être OK, mais il faut garder un œil dessus ...",
|
"diagnosis_regenconf_manually_modified_debian_details": "Cela peut probablement être OK, mais il faut garder un œil dessus …",
|
||||||
"diagnosis_security_all_good": "Aucune vulnérabilité de sécurité critique n'a été trouvée.",
|
"diagnosis_security_all_good": "Aucune vulnérabilité de sécurité critique n’a été trouvée.",
|
||||||
"apps_catalog_init_success": "Système de catalogue d'applications initialisé !",
|
"apps_catalog_init_success": "Système de catalogue d’applications initialisé !",
|
||||||
"apps_catalog_failed_to_download": "Impossible de télécharger le catalogue des applications {apps_catalog}:{error}",
|
"apps_catalog_failed_to_download": "Impossible de télécharger le catalogue des applications {apps_catalog}:{error}",
|
||||||
"diagnosis_mail_ougoing_port_25_blocked": "Le port sortant 25 semble être bloqué. Vous devriez essayer de le débloquer dans le panneau de configuration de votre fournisseur de services Internet (ou hébergeur). En attendant, le serveur ne pourra pas envoyer de courrier électronique à d'autres serveurs.",
|
"diagnosis_mail_outgoing_port_25_blocked": "Le port sortant 25 semble être bloqué. Vous devriez essayer de le débloquer dans le panneau de configuration de votre fournisseur de services Internet (ou hébergeur). En attendant, le serveur ne pourra pas envoyer de courrier électronique à d’autres serveurs.",
|
||||||
"domain_cannot_remove_main_add_new_one": "Vous ne pouvez pas supprimer '{domain:s}' car il s'agit du domaine principal et de votre seul domaine. Vous devez d'abord ajouter un autre domaine à l'aide de 'yunohost domain add <another-domain.com>', puis définir comme domaine principal à l'aide de ' yunohost domain main-domain -n <nomd'un-autre-domaine.com>' et vous pouvez ensuite supprimer le domaine '{domain:s}' à l'aide de 'yunohost domain remove {domain:s}'.'",
|
"domain_cannot_remove_main_add_new_one": "Vous ne pouvez pas supprimer '{domain:s}' car il s’agit du domaine principal et de votre seul domaine. Vous devez d’abord ajouter un autre domaine à l’aide de 'yunohost domain add <another-domain.com>', puis définir comme domaine principal à l’aide de 'yunohost domain main-domain -n <nom-d’un-autre-domaine.com>' et vous pouvez ensuite supprimer le domaine '{domain:s}' à l’aide de 'yunohost domain remove {domain:s}'.",
|
||||||
"diagnosis_security_vulnerable_to_meltdown_details": "Pour résoudre ce problème, vous devez mettre à niveau votre système et redémarrer pour charger le nouveau noyau Linux (ou contacter votre fournisseur de serveur si cela ne fonctionne pas). Voir https://meltdownattack.com/ pour plus d'informations.",
|
"diagnosis_security_vulnerable_to_meltdown_details": "Pour résoudre ce problème, vous devez mettre à niveau votre système et redémarrer pour charger le nouveau noyau Linux (ou contacter votre fournisseur de serveur si cela ne fonctionne pas). Voir https://meltdownattack.com/ pour plus d’informations.",
|
||||||
"diagnosis_description_basesystem": "Système de base",
|
"diagnosis_description_basesystem": "Système de base",
|
||||||
"diagnosis_description_ip": "Connectivité Internet",
|
"diagnosis_description_ip": "Connectivité Internet",
|
||||||
"diagnosis_description_dnsrecords": "Enregistrements DNS",
|
"diagnosis_description_dnsrecords": "Enregistrements DNS",
|
||||||
|
@ -562,41 +571,42 @@
|
||||||
"diagnosis_description_ports": "Exposition des ports",
|
"diagnosis_description_ports": "Exposition des ports",
|
||||||
"diagnosis_description_regenconf": "Configurations système",
|
"diagnosis_description_regenconf": "Configurations système",
|
||||||
"diagnosis_description_security": "Contrôles de sécurité",
|
"diagnosis_description_security": "Contrôles de sécurité",
|
||||||
"diagnosis_ports_could_not_diagnose": "Impossible de diagnostiquer si les ports sont accessibles de l'extérieur. Erreur: {error}",
|
"diagnosis_ports_could_not_diagnose": "Impossible de diagnostiquer si les ports sont accessibles de l'extérieur.",
|
||||||
|
"diagnosis_ports_could_not_diagnose_details": "Erreur: {error}",
|
||||||
"apps_catalog_updating": "Mise à jour du catalogue d'applications…",
|
"apps_catalog_updating": "Mise à jour du catalogue d'applications…",
|
||||||
"apps_catalog_obsolete_cache": "Le cache du catalogue d'applications est vide ou obsolète.",
|
"apps_catalog_obsolete_cache": "Le cache du catalogue d'applications est vide ou obsolète.",
|
||||||
"apps_catalog_update_success": "Le catalogue des applications a été mis à jour !",
|
"apps_catalog_update_success": "Le catalogue des applications a été mis à jour !",
|
||||||
"diagnosis_mail_ougoing_port_25_ok": "Le port sortant 25 n'est pas bloqué et le courrier électronique peut être envoyé à d'autres serveurs.",
|
"diagnosis_mail_ougoing_port_25_ok": "Le port sortant 25 n’est pas bloqué et le courrier électronique peut être envoyé à d’autres serveurs.",
|
||||||
"diagnosis_description_mail": "Email",
|
"diagnosis_description_mail": "Email",
|
||||||
"diagnosis_ports_unreachable": "Le port {port} n'est pas accessible de l'extérieur.",
|
"diagnosis_ports_unreachable": "Le port {port} n’est pas accessible de l’extérieur.",
|
||||||
"diagnosis_ports_ok": "Le port {port} est accessible de l'extérieur.",
|
"diagnosis_ports_ok": "Le port {port} est accessible de l’extérieur.",
|
||||||
"diagnosis_http_could_not_diagnose": "Impossible de diagnostiquer si le domaine est accessible de l'extérieur. Erreur: {error}",
|
"diagnosis_http_could_not_diagnose": "Impossible de diagnostiquer si le domaine est accessible de l’extérieur.",
|
||||||
"diagnosis_http_ok": "Le domaine {domain} est accessible au travers de HTTP depuis l'extérieur.",
|
"diagnosis_http_could_not_diagnose_details": "Erreur: {error}",
|
||||||
"diagnosis_http_unreachable": "Le domaine {domain} est inaccessible au travers de HTTP depuis l'extérieur.",
|
"diagnosis_http_ok": "Le domaine {domain} est accessible en HTTP depuis l’extérieur.",
|
||||||
|
"diagnosis_http_unreachable": "Le domaine {domain} est inaccessible en HTTP depuis l’extérieur.",
|
||||||
"diagnosis_unknown_categories": "Les catégories suivantes sont inconnues: {categories}",
|
"diagnosis_unknown_categories": "Les catégories suivantes sont inconnues: {categories}",
|
||||||
"migration_description_0013_futureproof_apps_catalog_system": "Migrer vers le nouveau système de catalogue d'applications à l'épreuve du temps",
|
"migration_description_0013_futureproof_apps_catalog_system": "Migrer vers le nouveau système de catalogue d’applications à l’épreuve du temps",
|
||||||
"app_upgrade_script_failed": "Une erreur s'est produite durant l’exécution du script de mise à niveau de l'application",
|
"app_upgrade_script_failed": "Une erreur s’est produite durant l’exécution du script de mise à niveau de l’application",
|
||||||
"migration_description_0014_remove_app_status_json": "Supprimer les fichiers d'application status.json hérités",
|
"migration_description_0014_remove_app_status_json": "Supprimer les anciens fichiers d’application status.json",
|
||||||
"diagnosis_services_running": "Le service {service} s'exécute correctement !",
|
"diagnosis_services_running": "Le service {service} est en cours de fonctionnement !",
|
||||||
"diagnosis_services_conf_broken": "La configuration est cassée pour le service {service} !",
|
"diagnosis_services_conf_broken": "La configuration est cassée pour le service {service} !",
|
||||||
"diagnosis_ports_needed_by": "Rendre ce port accessible est nécessaire pour les fonctionnalités de type {1} (service {0})",
|
"diagnosis_ports_needed_by": "Rendre ce port accessible est nécessaire pour les fonctionnalités de type {category} (service {service})",
|
||||||
"diagnosis_ports_forwarding_tip": "Pour résoudre ce problème, vous devez probablement configurer la redirection de port sur votre routeur Internet comme décrit sur https://yunohost.org/isp_box_config",
|
"diagnosis_ports_forwarding_tip": "Pour résoudre ce problème, vous devez probablement configurer la redirection de port sur votre routeur Internet comme décrit sur https://yunohost.org/isp_box_config",
|
||||||
"diagnosis_http_connection_error": "Erreur de connexion : impossible de se connecter au domaine demandé, il est probablement injoignable.",
|
"diagnosis_http_connection_error": "Erreur de connexion : impossible de se connecter au domaine demandé, il est probablement injoignable.",
|
||||||
"diagnosis_no_cache": "Pas encore de cache de diagnostique pour la catégorie « {category} »",
|
"diagnosis_no_cache": "Pas encore de cache de diagnostique pour la catégorie « {category} »",
|
||||||
"diagnosis_http_unknown_error": "Une erreur est survenue en essayant de joindre votre domaine, il est probablement injoignable.",
|
"yunohost_postinstall_end_tip": "La post-installation terminée! Pour finaliser votre configuration, il est recommendé de :\n - ajouter un premier utilisateur depuis la section \"Utilisateurs\" de l’interface web (ou \"yunohost user create <nom d’utilisateur>\" en ligne de commande);\n - diagnostiquer les potentiels problèmes dans la section \"Diagnostic\" de l'interface web (ou \"yunohost diagnosis run\" en ligne de commande);\n - lire les parties \"Finalisation de votre configuration\" et \"Découverte de Yunohost\" dans le guide de l’administrateur: https://yunohost.org/admindoc.",
|
||||||
"yunohost_postinstall_end_tip": "La post-installation terminée! Pour finaliser votre configuration, il est recommendé de :\n - ajouter un premier utilisateur depuis la section \"Utilisateurs\" de l'interface web (ou \"yunohost user create <nom d'utilisateur>\" en ligne de commande);\n - diagnostiquer les potentiels problèmes dans la section \"Diagnostic\" de l'interface web (ou \"yunohost diagnosis run\" en ligne de commande);\n - lire les parties \"Finalisation de votre configuration\" et \"Découverte de Yunohost\" dans le guide de l'administrateur: https://yunohost.org/admindoc.",
|
"diagnosis_services_bad_status_tip": "Vous pouvez essayer de redémarrer le service. Si cela ne fonctionne pas, consultez les journaux de service à l’aide de 'yunohost service log {service}' ou de la section 'Services' dans la webadmin.",
|
||||||
"diagnosis_services_bad_status_tip": "Vous pouvez essayer de redémarrer le service. Si cela ne fonctionne pas, consultez les journaux de service à l'aide de 'yunohost service log {0}' ou de la section 'Services' de l'administrateur Web.",
|
"diagnosis_http_bad_status_code": "Le système de diagnostique n’a pas réussi à contacter votre serveur. Il se peut qu’une autre machine réponde à la place de votre serveur. Vérifiez que le port 80 est correctement redirigé, que votre configuration nginx est à jour et qu’un reverse-proxy n’interfère pas.",
|
||||||
"diagnosis_http_bad_status_code": "Le système de diagnostique n'a pas réussi à contacter votre serveur. Il se peut qu'une autre machine réponde à la place de votre serveur. Vérifiez que le port 80 est correctement redirigé, que votre configuration nginx est à jour et qu’un reverse-proxy n’interfère pas.",
|
"diagnosis_http_timeout": "Expiration du délai en essayant de contacter votre serveur de l’extérieur. Il semble être inaccessible. Vérifiez que vous transférez correctement le port 80, que nginx est en cours d’exécution et qu’un pare-feu n’interfère pas.",
|
||||||
"diagnosis_http_timeout": "Expiration du délai en essayant de contacter votre serveur de l'extérieur. Il semble être inaccessible. Vérifiez que vous transférez correctement le port 80, que nginx est en cours d’exécution et qu’un pare-feu n’interfère pas.",
|
|
||||||
"global_settings_setting_pop3_enabled": "Activer le protocole POP3 pour le serveur de messagerie",
|
"global_settings_setting_pop3_enabled": "Activer le protocole POP3 pour le serveur de messagerie",
|
||||||
"log_app_action_run": "Lancer l’action de l’application '{}'",
|
"log_app_action_run": "Lancer l’action de l’application '{}'",
|
||||||
"log_app_config_show_panel": "Montrer le panneau de configuration de l’application '{}'",
|
"log_app_config_show_panel": "Montrer le panneau de configuration de l’application '{}'",
|
||||||
"log_app_config_apply": "Appliquer la configuration à l’application '{}'",
|
"log_app_config_apply": "Appliquer la configuration à l’application '{}'",
|
||||||
"diagnosis_never_ran_yet": "Il apparaît que le serveur a été installé récemment et qu'il n'y a pas encore eu de diagnostic. Vous devriez en lancer un depuis le webmin ou en utilisant 'yunohost diagnosis run' depuis la ligne de commande.",
|
"diagnosis_never_ran_yet": "Il apparaît que le serveur a été installé récemment et qu’il n’y a pas encore eu de diagnostic. Vous devriez en lancer un depuis le webmin ou en utilisant 'yunohost diagnosis run' depuis la ligne de commande.",
|
||||||
"diagnosis_description_web": "Web",
|
"diagnosis_description_web": "Web",
|
||||||
"diagnosis_basesystem_hardware_board": "Le modèle de carte du serveur est {model}",
|
"diagnosis_basesystem_hardware_board": "Le modèle de carte du serveur est {model}",
|
||||||
"diagnosis_basesystem_hardware": "L'architecture du serveur est {virt} {arch}",
|
"diagnosis_basesystem_hardware": "L’architecture du serveur est {virt} {arch}",
|
||||||
"group_already_exist_on_system_but_removing_it": "Le groupe {group} est déjà présent dans les groupes du système, mais Yuhonost va le supprimer…",
|
"group_already_exist_on_system_but_removing_it": "Le groupe {group} est déjà présent dans les groupes du système, mais YunoHost va le supprimer…",
|
||||||
"certmanager_warning_subdomain_dns_record": "Le sous-domaine '{subdomain:s}' ne résout pas vers la même adresse IP que '{domain:s}'. Certaines fonctionnalités seront indisponibles tant que vous n’aurez pas corrigé cela et regénéré le certificat.",
|
"certmanager_warning_subdomain_dns_record": "Le sous-domaine '{subdomain:s}' ne résout pas vers la même adresse IP que '{domain:s}'. Certaines fonctionnalités seront indisponibles tant que vous n’aurez pas corrigé cela et regénéré le certificat.",
|
||||||
"domain_cannot_add_xmpp_upload": "Vous ne pouvez pas ajouter de domaine commençant par 'xmpp-upload.'. Ce type de nom est réservé à la fonctionnalité d’upload XMPP intégrée dans Yunohost."
|
"domain_cannot_add_xmpp_upload": "Vous ne pouvez pas ajouter de domaine commençant par 'xmpp-upload.'. Ce type de nom est réservé à la fonctionnalité d’upload XMPP intégrée dans YunoHost."
|
||||||
}
|
}
|
||||||
|
|
|
@ -479,8 +479,8 @@
|
||||||
"diagnosis_http_ok": "Lo domeni {domain} accessible de l’exterior.",
|
"diagnosis_http_ok": "Lo domeni {domain} accessible de l’exterior.",
|
||||||
"app_full_domain_unavailable": "Aquesta aplicacion a d’èsser installada sul seu pròpri domeni, mas i a d’autras aplicacions installadas sus aqueste domeni « {domain} ». Podètz utilizar allòc un josdomeni dedicat a aquesta aplicacion.",
|
"app_full_domain_unavailable": "Aquesta aplicacion a d’èsser installada sul seu pròpri domeni, mas i a d’autras aplicacions installadas sus aqueste domeni « {domain} ». Podètz utilizar allòc un josdomeni dedicat a aquesta aplicacion.",
|
||||||
"diagnosis_dns_bad_conf": "Configuracion DNS incorrècta o inexistenta pel domeni {domain} (categoria {category})",
|
"diagnosis_dns_bad_conf": "Configuracion DNS incorrècta o inexistenta pel domeni {domain} (categoria {category})",
|
||||||
"diagnosis_ram_verylow": "Lo sistèma a solament {available_abs_MB} Mo ({available_percent}%) de memòria RAM disponibla ! (d’un total de {total_abs_MB} MB)",
|
"diagnosis_ram_verylow": "Lo sistèma a solament {available} ({available_percent}%) de memòria RAM disponibla ! (d’un total de {total})",
|
||||||
"diagnosis_ram_ok": "Lo sistèma a encara {available_abs_MB} Mo ({available_percent}%) de memòria RAM disponibla d’un total de {total_abs_MB} MB).",
|
"diagnosis_ram_ok": "Lo sistèma a encara {available} ({available_percent}%) de memòria RAM disponibla d’un total de {total}).",
|
||||||
"permission_already_allowed": "Lo grop « {group} » a ja la permission « {permission} » activada",
|
"permission_already_allowed": "Lo grop « {group} » a ja la permission « {permission} » activada",
|
||||||
"permission_already_disallowed": "Lo grop « {group} » a ja la permission « {permission} » desactivada",
|
"permission_already_disallowed": "Lo grop « {group} » a ja la permission « {permission} » desactivada",
|
||||||
"permission_cannot_remove_main": "La supression d’una permission màger es pas autorizada",
|
"permission_cannot_remove_main": "La supression d’una permission màger es pas autorizada",
|
||||||
|
@ -497,7 +497,7 @@
|
||||||
"user_already_exists": "L’utilizaire {user} existís ja",
|
"user_already_exists": "L’utilizaire {user} existís ja",
|
||||||
"diagnosis_basesystem_host": "Lo servidor fonciona amb Debian {debian_version}.",
|
"diagnosis_basesystem_host": "Lo servidor fonciona amb Debian {debian_version}.",
|
||||||
"diagnosis_basesystem_kernel": "Lo servidor fonciona amb lo nuclèu Linuxl {kernel_version}",
|
"diagnosis_basesystem_kernel": "Lo servidor fonciona amb lo nuclèu Linuxl {kernel_version}",
|
||||||
"diagnosis_basesystem_ynh_single_version": "{0} version : {1} ({2})",
|
"diagnosis_basesystem_ynh_single_version": "{package} version : {version} ({repo})",
|
||||||
"diagnosis_basesystem_ynh_inconsistent_versions": "Utilizatz de versions inconsistentas dels paquets de YunoHost… probablament a causa d'una actualizacion fracassada o parciala.",
|
"diagnosis_basesystem_ynh_inconsistent_versions": "Utilizatz de versions inconsistentas dels paquets de YunoHost… probablament a causa d'una actualizacion fracassada o parciala.",
|
||||||
"diagnosis_display_tip_cli": "Podètz executar « yunohost diagnosis show --issues » per mostrar las errors trobadas.",
|
"diagnosis_display_tip_cli": "Podètz executar « yunohost diagnosis show --issues » per mostrar las errors trobadas.",
|
||||||
"diagnosis_ignored_issues": "(+ {nb_ignored} problèma(es) ignorat(s))",
|
"diagnosis_ignored_issues": "(+ {nb_ignored} problèma(es) ignorat(s))",
|
||||||
|
@ -511,7 +511,7 @@
|
||||||
"diagnosis_cache_still_valid": "(Memòria cache totjorn valida pel diagnostic {category}. Cap d’autre diagnostic pel moment !)",
|
"diagnosis_cache_still_valid": "(Memòria cache totjorn valida pel diagnostic {category}. Cap d’autre diagnostic pel moment !)",
|
||||||
"diagnosis_found_errors": "{errors} errors importantas trobadas ligadas a {category} !",
|
"diagnosis_found_errors": "{errors} errors importantas trobadas ligadas a {category} !",
|
||||||
"diagnosis_services_bad_status": "Lo servici {service} es {status} :(",
|
"diagnosis_services_bad_status": "Lo servici {service} es {status} :(",
|
||||||
"diagnosis_swap_ok": "Lo sistèma a {total_MB} MB d’escambi !",
|
"diagnosis_swap_ok": "Lo sistèma a {total} d’escambi !",
|
||||||
"diagnosis_regenconf_allgood": "Totes los fichièrs de configuracion son confòrmes a la configuracion recomandada !",
|
"diagnosis_regenconf_allgood": "Totes los fichièrs de configuracion son confòrmes a la configuracion recomandada !",
|
||||||
"diagnosis_regenconf_manually_modified": "Lo fichièr de configuracion {file} foguèt modificat manualament.",
|
"diagnosis_regenconf_manually_modified": "Lo fichièr de configuracion {file} foguèt modificat manualament.",
|
||||||
"diagnosis_regenconf_manually_modified_details": "Es probablament bon tan que sabètz çò que fasètz ;) !",
|
"diagnosis_regenconf_manually_modified_details": "Es probablament bon tan que sabètz çò que fasètz ;) !",
|
||||||
|
@ -527,7 +527,7 @@
|
||||||
"diagnosis_ports_ok": "Lo pòrt {port} es accessible de l’exterior.",
|
"diagnosis_ports_ok": "Lo pòrt {port} es accessible de l’exterior.",
|
||||||
"diagnosis_http_unreachable": "Lo domeni {domain} es pas accessible via HTTP de l’exterior.",
|
"diagnosis_http_unreachable": "Lo domeni {domain} es pas accessible via HTTP de l’exterior.",
|
||||||
"diagnosis_unknown_categories": "La categorias seguentas son desconegudas : {categories}",
|
"diagnosis_unknown_categories": "La categorias seguentas son desconegudas : {categories}",
|
||||||
"diagnosis_ram_low": "Lo sistèma a {available_abs_MB} Mo ({available_percent}%) de memòria RAM disponibla d’un total de {total_abs_MB} MB). Atencion.",
|
"diagnosis_ram_low": "Lo sistèma a {available} ({available_percent}%) de memòria RAM disponibla d’un total de {total}). Atencion.",
|
||||||
"diagnosis_regenconf_manually_modified_debian": "Lo fichier de configuracion {file} foguèt modificat manualament respècte al fichièr per defaut de Debian.",
|
"diagnosis_regenconf_manually_modified_debian": "Lo fichier de configuracion {file} foguèt modificat manualament respècte al fichièr per defaut de Debian.",
|
||||||
"log_permission_create": "Crear la permission « {} »",
|
"log_permission_create": "Crear la permission « {} »",
|
||||||
"log_permission_delete": "Suprimir la permission « {} »",
|
"log_permission_delete": "Suprimir la permission « {} »",
|
||||||
|
@ -536,11 +536,13 @@
|
||||||
"operation_interrupted": "L’operacion es estada interrompuda manualament ?",
|
"operation_interrupted": "L’operacion es estada interrompuda manualament ?",
|
||||||
"group_cannot_be_deleted": "Lo grop « {group} » pòt pas èsser suprimit manualament.",
|
"group_cannot_be_deleted": "Lo grop « {group} » pòt pas èsser suprimit manualament.",
|
||||||
"diagnosis_found_warnings": "Trobat {warnings} element(s) que se poirián melhorar per {category}.",
|
"diagnosis_found_warnings": "Trobat {warnings} element(s) que se poirián melhorar per {category}.",
|
||||||
"diagnosis_dns_missing_record": "Segon la configuracion DNS recomandada, vos calriá ajustar un enregistrament DNS de tipe {0}, nom {1} e valor {2}. Podètz consultar https://yunohost.org/dns_config per mai d’informacions.",
|
"diagnosis_dns_missing_record": "Segon la configuracion DNS recomandada, vos calriá ajustar un enregistrament DNS\ntipe: {type}\nnom: {name}\nvalor: {value}",
|
||||||
"diagnosis_dns_discrepancy": "Segon la configuracion DNS recomandada, la valor per l’enregistrament DNS de tipe {0} e nom {1} deuriá èsser {2} allòc de {3}.",
|
"diagnosis_dns_discrepancy": "Segon la configuracion DNS recomandada, la valor per l’enregistrament DNS\ntipe: {type}\nnom: {name}\ndeuriá èsser: {current}\nallòc de: {value}",
|
||||||
"diagnosis_regenconf_manually_modified_debian_details": "Es pas problematic, mas car téner d’agacher...",
|
"diagnosis_regenconf_manually_modified_debian_details": "Es pas problematic, mas car téner d’agacher...",
|
||||||
"diagnosis_ports_could_not_diagnose": "Impossible de diagnosticar se los pòrts son accessibles de l’exterior. Error : {error}",
|
"diagnosis_ports_could_not_diagnose": "Impossible de diagnosticar se los pòrts son accessibles de l’exterior.",
|
||||||
"diagnosis_http_could_not_diagnose": "Impossible de diagnosticar se lo domeni es accessible de l’exterior. Error : {error}",
|
"diagnosis_ports_could_not_diagnose_details": "Error : {error}",
|
||||||
|
"diagnosis_http_could_not_diagnose": "Impossible de diagnosticar se lo domeni es accessible de l’exterior.",
|
||||||
|
"diagnosis_http_could_not_diagnose_details": "Error : {error}",
|
||||||
"apps_catalog_updating": "Actualizacion del catalòg d’aplicacion…",
|
"apps_catalog_updating": "Actualizacion del catalòg d’aplicacion…",
|
||||||
"apps_catalog_failed_to_download": "Telecargament impossible del catalòg d’aplicacions {apps_catalog} : {error}",
|
"apps_catalog_failed_to_download": "Telecargament impossible del catalòg d’aplicacions {apps_catalog} : {error}",
|
||||||
"apps_catalog_obsolete_cache": "La memòria cache del catalòg d’aplicacion es voida o obsolèta.",
|
"apps_catalog_obsolete_cache": "La memòria cache del catalòg d’aplicacion es voida o obsolèta.",
|
||||||
|
@ -556,19 +558,18 @@
|
||||||
"apps_catalog_init_success": "Sistèma de catalòg d’aplicacion iniciat !",
|
"apps_catalog_init_success": "Sistèma de catalòg d’aplicacion iniciat !",
|
||||||
"diagnosis_services_running": "Lo servici {service} es lançat !",
|
"diagnosis_services_running": "Lo servici {service} es lançat !",
|
||||||
"diagnosis_services_conf_broken": "La configuracion es copada pel servici {service} !",
|
"diagnosis_services_conf_broken": "La configuracion es copada pel servici {service} !",
|
||||||
"diagnosis_ports_needed_by": "Es necessari qu’aqueste pòrt siá accessible pel servici {0}",
|
"diagnosis_ports_needed_by": "Es necessari qu’aqueste pòrt siá accessible pel servici {service}",
|
||||||
"diagnosis_diskusage_low": "Lo lòc d’emmagazinatge {mountpoint} (sul periferic {device}) a solament {free_abs_GB} Go ({free_percent}%). Siatz prudent.",
|
"diagnosis_diskusage_low": "Lo lòc d’emmagazinatge {mountpoint} (sul periferic {device}) a solament {free} ({free_percent}%). Siatz prudent.",
|
||||||
"migration_description_0014_remove_app_status_json": "Suprimir los fichièrs d’aplicacion status.json eretats",
|
"migration_description_0014_remove_app_status_json": "Suprimir los fichièrs d’aplicacion status.json eretats",
|
||||||
"dyndns_provider_unreachable": "Impossible d’atenher lo provesidor Dyndns : siá vòstre YunoHost es pas corrèctament connectat a Internet siá lo servidor dynette es copat.",
|
"dyndns_provider_unreachable": "Impossible d’atenher lo provesidor Dyndns : siá vòstre YunoHost es pas corrèctament connectat a Internet siá lo servidor dynette es copat.",
|
||||||
"diagnosis_services_bad_status_tip": "Podètz ensajar de reaviar lo servici, e se non fonciona pas, podètz agachar los jornals en utilizant « yunohost service log {0} » o via la seccion « Servicis » de pas la pagina web d’administracion.",
|
"diagnosis_services_bad_status_tip": "Podètz ensajar de reaviar lo servici, e se non fonciona pas, podètz agachar los jornals en utilizant « yunohost service log {service} » o via la seccion « Servicis » de pas la pagina web d’administracion.",
|
||||||
"diagnosis_http_connection_error": "Error de connexion : connexion impossibla al domeni demandat, benlèu qu’es pas accessible.",
|
"diagnosis_http_connection_error": "Error de connexion : connexion impossibla al domeni demandat, benlèu qu’es pas accessible.",
|
||||||
"diagnosis_http_unknown_error": "Una error s’es producha en ensajar de se connectar a vòstre domeni, es benlèu pas accessible.",
|
|
||||||
"group_user_already_in_group": "L’utilizaire {user} es ja dins lo grop « {group} »",
|
"group_user_already_in_group": "L’utilizaire {user} es ja dins lo grop « {group} »",
|
||||||
"diagnosis_ip_broken_resolvconf": "La resolucion del nom de domeni sembla copada sul servidor, poiriá èsser ligada al fait que /etc/resolv.conf manda pas a 127.0.0.1.",
|
"diagnosis_ip_broken_resolvconf": "La resolucion del nom de domeni sembla copada sul servidor, poiriá èsser ligada al fait que /etc/resolv.conf manda pas a 127.0.0.1.",
|
||||||
"diagnosis_ip_weird_resolvconf": "La resolucion del nom de domeni sembla foncionar, mas siatz prudent en utilizant un fichièr /etc/resolv.con personalizat.",
|
"diagnosis_ip_weird_resolvconf": "La resolucion del nom de domeni sembla foncionar, mas siatz prudent en utilizant un fichièr /etc/resolv.con personalizat.",
|
||||||
"diagnosis_diskusage_verylow": "Lo lòc d’emmagazinatge {mountpoint} (sul periferic {device}) a solament {free_abs_GB} Go ({free_percent}%). Deuriatz considerar de liberar un pauc d’espaci.",
|
"diagnosis_diskusage_verylow": "Lo lòc d’emmagazinatge {mountpoint} (sul periferic {device}) a solament {free} ({free_percent}%). Deuriatz considerar de liberar un pauc d’espaci.",
|
||||||
"global_settings_setting_pop3_enabled": "Activar lo protocòl POP3 pel servidor de corrièr",
|
"global_settings_setting_pop3_enabled": "Activar lo protocòl POP3 pel servidor de corrièr",
|
||||||
"diagnosis_diskusage_ok": "Lo lòc d’emmagazinatge {mountpoint} (sul periferic {device}) a encara {free_abs_GB} Go ({free_percent}%) de liure !",
|
"diagnosis_diskusage_ok": "Lo lòc d’emmagazinatge {mountpoint} (sul periferic {device}) a encara {free} ({free_percent}%) de liure !",
|
||||||
"diagnosis_swap_none": "Lo sistèma a pas cap de memòria d’escambi. Auriatz de considerar d’ajustar almens 256 Mo d’escambi per evitar las situacions ont lo sistèma manca de memòria.",
|
"diagnosis_swap_none": "Lo sistèma a pas cap de memòria d’escambi. Auriatz de considerar d’ajustar almens {recommended} d’escambi per evitar las situacions ont lo sistèma manca de memòria.",
|
||||||
"diagnosis_swap_notsomuch": "Lo sistèma a solament {total_MB} de memòria d’escambi. Auriatz de considerar d’ajustar almens 256 Mo d’escambi per evitar las situacions ont lo sistèma manca de memòria."
|
"diagnosis_swap_notsomuch": "Lo sistèma a solament {total} de memòria d’escambi. Auriatz de considerar d’ajustar almens {recommended} d’escambi per evitar las situacions ont lo sistèma manca de memòria."
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,12 +110,34 @@ def app_catalog(full=False, with_categories=False):
|
||||||
return {"apps": catalog["apps"], "categories": catalog["categories"]}
|
return {"apps": catalog["apps"], "categories": catalog["categories"]}
|
||||||
|
|
||||||
|
|
||||||
def app_list(full=False):
|
|
||||||
|
# Old legacy function...
|
||||||
|
def app_fetchlist():
|
||||||
|
logger.warning("'yunohost app fetchlist' is deprecated. Please use 'yunohost tools update --apps' instead")
|
||||||
|
from yunohost.tools import tools_update
|
||||||
|
tools_update(apps=True)
|
||||||
|
|
||||||
|
|
||||||
|
def app_list(full=False, installed=False, filter=None):
|
||||||
"""
|
"""
|
||||||
List installed apps
|
List installed apps
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Old legacy argument ... app_list was a combination of app_list and
|
||||||
|
# app_catalog before 3.8 ...
|
||||||
|
if installed:
|
||||||
|
logger.warning("Argument --installed ain't needed anymore when using 'yunohost app list'. It directly returns the list of installed apps..")
|
||||||
|
|
||||||
|
# Filter is a deprecated option...
|
||||||
|
if filter:
|
||||||
|
logger.warning("Using -f $appname in 'yunohost app list' is deprecated. Just use 'yunohost app list | grep -q 'id: $appname' to check a specific app is installed")
|
||||||
|
|
||||||
out = []
|
out = []
|
||||||
for app_id in sorted(_installed_apps()):
|
for app_id in sorted(_installed_apps()):
|
||||||
|
|
||||||
|
if filter and not app_id.startswith(filter):
|
||||||
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
app_info_dict = app_info(app_id, full=full)
|
app_info_dict = app_info(app_id, full=full)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -239,6 +261,8 @@ def app_map(app=None, raw=False, user=None):
|
||||||
perm_domain, perm_path = perm_url.split("/", 1)
|
perm_domain, perm_path = perm_url.split("/", 1)
|
||||||
perm_path = "/" + perm_path.rstrip("/")
|
perm_path = "/" + perm_path.rstrip("/")
|
||||||
|
|
||||||
|
perm_path = perm_path if perm_path.strip() != "" else "/"
|
||||||
|
|
||||||
return perm_domain, perm_path
|
return perm_domain, perm_path
|
||||||
|
|
||||||
this_app_perms = {p: i for p, i in permissions.items() if p.startswith(app_id + ".") and i["url"]}
|
this_app_perms = {p: i for p, i in permissions.items() if p.startswith(app_id + ".") and i["url"]}
|
||||||
|
@ -274,7 +298,6 @@ def app_map(app=None, raw=False, user=None):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
perm_domain, perm_path = _sanitized_absolute_url(perm_info["url"])
|
perm_domain, perm_path = _sanitized_absolute_url(perm_info["url"])
|
||||||
|
|
||||||
if perm_name.endswith(".main"):
|
if perm_name.endswith(".main"):
|
||||||
perm_label = label
|
perm_label = label
|
||||||
else:
|
else:
|
||||||
|
@ -512,7 +535,7 @@ def app_upgrade(app=[], url=None, file=None):
|
||||||
upgrade_failed = True if upgrade_retcode != 0 else False
|
upgrade_failed = True if upgrade_retcode != 0 else False
|
||||||
if upgrade_failed:
|
if upgrade_failed:
|
||||||
error = m18n.n('app_upgrade_script_failed')
|
error = m18n.n('app_upgrade_script_failed')
|
||||||
logger.exception(m18n.n("app_upgrade_failed", app=app_instance_name, error=error))
|
logger.error(m18n.n("app_upgrade_failed", app=app_instance_name, error=error))
|
||||||
failure_message_with_debug_instructions = operation_logger.error(error)
|
failure_message_with_debug_instructions = operation_logger.error(error)
|
||||||
if msettings.get('interface') != 'api':
|
if msettings.get('interface') != 'api':
|
||||||
dump_app_log_extract_for_debugging(operation_logger)
|
dump_app_log_extract_for_debugging(operation_logger)
|
||||||
|
@ -520,13 +543,13 @@ def app_upgrade(app=[], url=None, file=None):
|
||||||
except (KeyboardInterrupt, EOFError):
|
except (KeyboardInterrupt, EOFError):
|
||||||
upgrade_retcode = -1
|
upgrade_retcode = -1
|
||||||
error = m18n.n('operation_interrupted')
|
error = m18n.n('operation_interrupted')
|
||||||
logger.exception(m18n.n("app_upgrade_failed", app=app_instance_name, error=error))
|
logger.error(m18n.n("app_upgrade_failed", app=app_instance_name, error=error))
|
||||||
failure_message_with_debug_instructions = operation_logger.error(error)
|
failure_message_with_debug_instructions = operation_logger.error(error)
|
||||||
# Something wrong happened in Yunohost's code (most probably hook_exec)
|
# Something wrong happened in Yunohost's code (most probably hook_exec)
|
||||||
except Exception:
|
except Exception:
|
||||||
import traceback
|
import traceback
|
||||||
error = m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())
|
error = m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())
|
||||||
logger.exception(m18n.n("app_install_failed", app=app_instance_name, error=error))
|
logger.error(m18n.n("app_install_failed", app=app_instance_name, error=error))
|
||||||
failure_message_with_debug_instructions = operation_logger.error(error)
|
failure_message_with_debug_instructions = operation_logger.error(error)
|
||||||
finally:
|
finally:
|
||||||
# Whatever happened (install success or failure) we check if it broke the system
|
# Whatever happened (install success or failure) we check if it broke the system
|
||||||
|
@ -536,7 +559,7 @@ def app_upgrade(app=[], url=None, file=None):
|
||||||
_assert_system_is_sane_for_app(manifest, "post")
|
_assert_system_is_sane_for_app(manifest, "post")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
broke_the_system = True
|
broke_the_system = True
|
||||||
logger.exception(m18n.n("app_upgrade_failed", app=app_instance_name, error=str(e)))
|
logger.error(m18n.n("app_upgrade_failed", app=app_instance_name, error=str(e)))
|
||||||
failure_message_with_debug_instructions = operation_logger.error(str(e))
|
failure_message_with_debug_instructions = operation_logger.error(str(e))
|
||||||
|
|
||||||
# If upgrade failed or broke the system,
|
# If upgrade failed or broke the system,
|
||||||
|
@ -768,20 +791,20 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu
|
||||||
install_failed = True if install_retcode != 0 else False
|
install_failed = True if install_retcode != 0 else False
|
||||||
if install_failed:
|
if install_failed:
|
||||||
error = m18n.n('app_install_script_failed')
|
error = m18n.n('app_install_script_failed')
|
||||||
logger.exception(m18n.n("app_install_failed", app=app_id, error=error))
|
logger.error(m18n.n("app_install_failed", app=app_id, error=error))
|
||||||
failure_message_with_debug_instructions = operation_logger.error(error)
|
failure_message_with_debug_instructions = operation_logger.error(error)
|
||||||
if msettings.get('interface') != 'api':
|
if msettings.get('interface') != 'api':
|
||||||
dump_app_log_extract_for_debugging(operation_logger)
|
dump_app_log_extract_for_debugging(operation_logger)
|
||||||
# Script got manually interrupted ... N.B. : KeyboardInterrupt does not inherit from Exception
|
# Script got manually interrupted ... N.B. : KeyboardInterrupt does not inherit from Exception
|
||||||
except (KeyboardInterrupt, EOFError):
|
except (KeyboardInterrupt, EOFError):
|
||||||
error = m18n.n('operation_interrupted')
|
error = m18n.n('operation_interrupted')
|
||||||
logger.exception(m18n.n("app_install_failed", app=app_id, error=error))
|
logger.error(m18n.n("app_install_failed", app=app_id, error=error))
|
||||||
failure_message_with_debug_instructions = operation_logger.error(error)
|
failure_message_with_debug_instructions = operation_logger.error(error)
|
||||||
# Something wrong happened in Yunohost's code (most probably hook_exec)
|
# Something wrong happened in Yunohost's code (most probably hook_exec)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
import traceback
|
import traceback
|
||||||
error = m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())
|
error = m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())
|
||||||
logger.exception(m18n.n("app_install_failed", app=app_id, error=error))
|
logger.error(m18n.n("app_install_failed", app=app_id, error=error))
|
||||||
failure_message_with_debug_instructions = operation_logger.error(error)
|
failure_message_with_debug_instructions = operation_logger.error(error)
|
||||||
finally:
|
finally:
|
||||||
# Whatever happened (install success or failure) we check if it broke the system
|
# Whatever happened (install success or failure) we check if it broke the system
|
||||||
|
@ -791,7 +814,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu
|
||||||
_assert_system_is_sane_for_app(manifest, "post")
|
_assert_system_is_sane_for_app(manifest, "post")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
broke_the_system = True
|
broke_the_system = True
|
||||||
logger.exception(m18n.n("app_install_failed", app=app_id, error=str(e)))
|
logger.error(m18n.n("app_install_failed", app=app_id, error=str(e)))
|
||||||
failure_message_with_debug_instructions = operation_logger.error(str(e))
|
failure_message_with_debug_instructions = operation_logger.error(str(e))
|
||||||
|
|
||||||
# If the install failed or broke the system, we remove it
|
# If the install failed or broke the system, we remove it
|
||||||
|
@ -828,7 +851,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu
|
||||||
except (KeyboardInterrupt, EOFError, Exception):
|
except (KeyboardInterrupt, EOFError, Exception):
|
||||||
remove_retcode = -1
|
remove_retcode = -1
|
||||||
import traceback
|
import traceback
|
||||||
logger.exception(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc()))
|
logger.error(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc()))
|
||||||
|
|
||||||
# Remove all permission in LDAP
|
# Remove all permission in LDAP
|
||||||
for permission_name in user_permission_list()["permissions"].keys():
|
for permission_name in user_permission_list()["permissions"].keys():
|
||||||
|
@ -999,7 +1022,7 @@ def app_remove(operation_logger, app):
|
||||||
except (KeyboardInterrupt, EOFError, Exception):
|
except (KeyboardInterrupt, EOFError, Exception):
|
||||||
ret = -1
|
ret = -1
|
||||||
import traceback
|
import traceback
|
||||||
logger.exception(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc()))
|
logger.error(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc()))
|
||||||
|
|
||||||
if ret == 0:
|
if ret == 0:
|
||||||
logger.success(m18n.n('app_removed', app=app))
|
logger.success(m18n.n('app_removed', app=app))
|
||||||
|
@ -1105,11 +1128,12 @@ def app_makedefault(operation_logger, app, domain=None):
|
||||||
elif domain not in domain_list()['domains']:
|
elif domain not in domain_list()['domains']:
|
||||||
raise YunohostError('domain_unknown')
|
raise YunohostError('domain_unknown')
|
||||||
|
|
||||||
operation_logger.start()
|
|
||||||
if '/' in app_map(raw=True)[domain]:
|
if '/' in app_map(raw=True)[domain]:
|
||||||
raise YunohostError('app_make_default_location_already_used', app=app, domain=app_domain,
|
raise YunohostError('app_make_default_location_already_used', app=app, domain=app_domain,
|
||||||
other_app=app_map(raw=True)[domain]["/"]["id"])
|
other_app=app_map(raw=True)[domain]["/"]["id"])
|
||||||
|
|
||||||
|
operation_logger.start()
|
||||||
|
|
||||||
# TODO / FIXME : current trick is to add this to conf.json.persisten
|
# TODO / FIXME : current trick is to add this to conf.json.persisten
|
||||||
# This is really not robust and should be improved
|
# This is really not robust and should be improved
|
||||||
# e.g. have a flag in /etc/yunohost/apps/$app/ to say that this is the
|
# e.g. have a flag in /etc/yunohost/apps/$app/ to say that this is the
|
||||||
|
@ -1267,6 +1291,8 @@ def app_ssowatconf():
|
||||||
perm_domain, perm_path = perm_url.split("/", 1)
|
perm_domain, perm_path = perm_url.split("/", 1)
|
||||||
perm_path = "/" + perm_path.rstrip("/")
|
perm_path = "/" + perm_path.rstrip("/")
|
||||||
|
|
||||||
|
perm_path = perm_path if perm_path.strip() != "" else "/"
|
||||||
|
|
||||||
return perm_domain + perm_path
|
return perm_domain + perm_path
|
||||||
|
|
||||||
# Skipped
|
# Skipped
|
||||||
|
@ -1825,7 +1851,7 @@ def _get_app_settings(app_id):
|
||||||
if app_id == settings['id']:
|
if app_id == settings['id']:
|
||||||
return settings
|
return settings
|
||||||
except (IOError, TypeError, KeyError):
|
except (IOError, TypeError, KeyError):
|
||||||
logger.exception(m18n.n('app_not_correctly_installed',
|
logger.error(m18n.n('app_not_correctly_installed',
|
||||||
app=app_id))
|
app=app_id))
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
|
@ -35,9 +35,9 @@ import tempfile
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
from moulinette import msignals, m18n, msettings
|
from moulinette import msignals, m18n, msettings
|
||||||
from yunohost.utils.error import YunohostError
|
|
||||||
from moulinette.utils import filesystem
|
from moulinette.utils import filesystem
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
from moulinette.utils.filesystem import read_file, mkdir, write_to_yaml, read_yaml
|
from moulinette.utils.filesystem import read_file, mkdir, write_to_yaml, read_yaml
|
||||||
|
@ -51,7 +51,8 @@ from yunohost.hook import (
|
||||||
from yunohost.tools import tools_postinstall
|
from yunohost.tools import tools_postinstall
|
||||||
from yunohost.regenconf import regen_conf
|
from yunohost.regenconf import regen_conf
|
||||||
from yunohost.log import OperationLogger
|
from yunohost.log import OperationLogger
|
||||||
from functools import reduce
|
from yunohost.utils.error import YunohostError
|
||||||
|
from yunohost.utils.packages import ynh_packages_version
|
||||||
|
|
||||||
BACKUP_PATH = '/home/yunohost.backup'
|
BACKUP_PATH = '/home/yunohost.backup'
|
||||||
ARCHIVES_PATH = '%s/archives' % BACKUP_PATH
|
ARCHIVES_PATH = '%s/archives' % BACKUP_PATH
|
||||||
|
@ -282,7 +283,8 @@ class BackupManager():
|
||||||
'size': self.size,
|
'size': self.size,
|
||||||
'size_details': self.size_details,
|
'size_details': self.size_details,
|
||||||
'apps': self.apps_return,
|
'apps': self.apps_return,
|
||||||
'system': self.system_return
|
'system': self.system_return,
|
||||||
|
'from_yunohost_version': ynh_packages_version()["yunohost"]["version"]
|
||||||
}
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -604,7 +606,7 @@ class BackupManager():
|
||||||
ret_succeed = {hook: [path for path, result in infos.items() if result["state"] == "succeed"]
|
ret_succeed = {hook: [path for path, result in infos.items() if result["state"] == "succeed"]
|
||||||
for hook, infos in ret.items()
|
for hook, infos in ret.items()
|
||||||
if any(result["state"] == "succeed" for result in infos.values())}
|
if any(result["state"] == "succeed" for result in infos.values())}
|
||||||
ret_failed = {hook: [path for path, result in infos.items.items() if result["state"] == "failed"]
|
ret_failed = {hook: [path for path, result in infos.items() if result["state"] == "failed"]
|
||||||
for hook, infos in ret.items()
|
for hook, infos in ret.items()
|
||||||
if any(result["state"] == "failed" for result in infos.values())}
|
if any(result["state"] == "failed" for result in infos.values())}
|
||||||
|
|
||||||
|
@ -870,7 +872,7 @@ class RestoreManager():
|
||||||
Read the info file from inside an archive
|
Read the info file from inside an archive
|
||||||
|
|
||||||
Exceptions:
|
Exceptions:
|
||||||
backup_invalid_archive -- Raised if we can't read the info
|
backup_archive_cant_retrieve_info_json -- Raised if we can't read the info
|
||||||
"""
|
"""
|
||||||
# Retrieve backup info
|
# Retrieve backup info
|
||||||
info_file = os.path.join(self.work_dir, "info.json")
|
info_file = os.path.join(self.work_dir, "info.json")
|
||||||
|
@ -883,7 +885,7 @@ class RestoreManager():
|
||||||
self.info["system"] = self.info["hooks"]
|
self.info["system"] = self.info["hooks"]
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.debug("unable to load '%s'", info_file, exc_info=1)
|
logger.debug("unable to load '%s'", info_file, exc_info=1)
|
||||||
raise YunohostError('backup_invalid_archive')
|
raise YunohostError('backup_archive_cant_retrieve_info_json', archive=self.archive_path)
|
||||||
else:
|
else:
|
||||||
logger.debug("restoring from backup '%s' created on %s", self.name,
|
logger.debug("restoring from backup '%s' created on %s", self.name,
|
||||||
datetime.utcfromtimestamp(self.info['created_at']))
|
datetime.utcfromtimestamp(self.info['created_at']))
|
||||||
|
@ -891,10 +893,6 @@ class RestoreManager():
|
||||||
def _postinstall_if_needed(self):
|
def _postinstall_if_needed(self):
|
||||||
"""
|
"""
|
||||||
Post install yunohost if needed
|
Post install yunohost if needed
|
||||||
|
|
||||||
Exceptions:
|
|
||||||
backup_invalid_archive -- Raised if the current_host isn't in the
|
|
||||||
archive
|
|
||||||
"""
|
"""
|
||||||
# Check if YunoHost is installed
|
# Check if YunoHost is installed
|
||||||
if not os.path.isfile('/etc/yunohost/installed'):
|
if not os.path.isfile('/etc/yunohost/installed'):
|
||||||
|
@ -906,7 +904,7 @@ class RestoreManager():
|
||||||
logger.debug("unable to retrieve current_host from the backup",
|
logger.debug("unable to retrieve current_host from the backup",
|
||||||
exc_info=1)
|
exc_info=1)
|
||||||
# FIXME include the current_host by default ?
|
# FIXME include the current_host by default ?
|
||||||
raise YunohostError('backup_invalid_archive')
|
raise YunohostError("The main domain name cannot be retrieved from inside the archive, and is needed to perform the postinstall", raw_msg=True)
|
||||||
|
|
||||||
logger.debug("executing the post-install...")
|
logger.debug("executing the post-install...")
|
||||||
tools_postinstall(domain, 'Yunohost', True)
|
tools_postinstall(domain, 'Yunohost', True)
|
||||||
|
@ -1913,6 +1911,8 @@ class TarBackupMethod(BackupMethod):
|
||||||
|
|
||||||
Exceptions:
|
Exceptions:
|
||||||
backup_archive_open_failed -- Raised if the archive can't be open
|
backup_archive_open_failed -- Raised if the archive can't be open
|
||||||
|
backup_archive_corrupted -- Raised if the archive appears corrupted
|
||||||
|
backup_archive_cant_retrieve_info_json -- If the info.json file can't be retrieved
|
||||||
"""
|
"""
|
||||||
super(TarBackupMethod, self).mount(restore_manager)
|
super(TarBackupMethod, self).mount(restore_manager)
|
||||||
|
|
||||||
|
@ -1924,6 +1924,11 @@ class TarBackupMethod(BackupMethod):
|
||||||
self._archive_file, exc_info=1)
|
self._archive_file, exc_info=1)
|
||||||
raise YunohostError('backup_archive_open_failed')
|
raise YunohostError('backup_archive_open_failed')
|
||||||
|
|
||||||
|
try:
|
||||||
|
files_in_archive = tar.getnames()
|
||||||
|
except IOError as e:
|
||||||
|
raise YunohostError("backup_archive_corrupted", archive=self._archive_file, error=str(e))
|
||||||
|
|
||||||
# FIXME : Is this really useful to close the archive just to
|
# FIXME : Is this really useful to close the archive just to
|
||||||
# reopen it right after this with the same options ...?
|
# reopen it right after this with the same options ...?
|
||||||
tar.close()
|
tar.close()
|
||||||
|
@ -1932,21 +1937,21 @@ class TarBackupMethod(BackupMethod):
|
||||||
logger.debug(m18n.n("restore_extracting"))
|
logger.debug(m18n.n("restore_extracting"))
|
||||||
tar = tarfile.open(self._archive_file, "r:gz")
|
tar = tarfile.open(self._archive_file, "r:gz")
|
||||||
|
|
||||||
if "info.json" in tar.getnames():
|
if "info.json" in files_in_archive:
|
||||||
leading_dot = ""
|
leading_dot = ""
|
||||||
tar.extract('info.json', path=self.work_dir)
|
tar.extract('info.json', path=self.work_dir)
|
||||||
elif "./info.json" in tar.getnames():
|
elif "./info.json" in files_in_archive:
|
||||||
leading_dot = "./"
|
leading_dot = "./"
|
||||||
tar.extract('./info.json', path=self.work_dir)
|
tar.extract('./info.json', path=self.work_dir)
|
||||||
else:
|
else:
|
||||||
logger.debug("unable to retrieve 'info.json' inside the archive",
|
logger.debug("unable to retrieve 'info.json' inside the archive",
|
||||||
exc_info=1)
|
exc_info=1)
|
||||||
tar.close()
|
tar.close()
|
||||||
raise YunohostError('backup_invalid_archive')
|
raise YunohostError('backup_archive_cant_retrieve_info_json', archive=self._archive_file)
|
||||||
|
|
||||||
if "backup.csv" in tar.getnames():
|
if "backup.csv" in files_in_archive:
|
||||||
tar.extract('backup.csv', path=self.work_dir)
|
tar.extract('backup.csv', path=self.work_dir)
|
||||||
elif "./backup.csv" in tar.getnames():
|
elif "./backup.csv" in files_in_archive:
|
||||||
tar.extract('./backup.csv', path=self.work_dir)
|
tar.extract('./backup.csv', path=self.work_dir)
|
||||||
else:
|
else:
|
||||||
# Old backup archive have no backup.csv file
|
# Old backup archive have no backup.csv file
|
||||||
|
@ -2288,7 +2293,7 @@ def backup_list(with_info=False, human_readable=False):
|
||||||
try:
|
try:
|
||||||
d[a] = backup_info(a, human_readable=human_readable)
|
d[a] = backup_info(a, human_readable=human_readable)
|
||||||
except YunohostError as e:
|
except YunohostError as e:
|
||||||
logger.warning('%s: %s' % (a, e.strerror))
|
logger.warning(str(e))
|
||||||
|
|
||||||
result = d
|
result = d
|
||||||
|
|
||||||
|
@ -2325,17 +2330,23 @@ def backup_info(name, with_details=False, human_readable=False):
|
||||||
if not os.path.exists(info_file):
|
if not os.path.exists(info_file):
|
||||||
tar = tarfile.open(archive_file, "r:gz")
|
tar = tarfile.open(archive_file, "r:gz")
|
||||||
info_dir = info_file + '.d'
|
info_dir = info_file + '.d'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if "info.json" in tar.getnames():
|
files_in_archive = tar.getnames()
|
||||||
|
except IOError as e:
|
||||||
|
raise YunohostError("backup_archive_corrupted", archive=archive_file, error=str(e))
|
||||||
|
|
||||||
|
try:
|
||||||
|
if "info.json" in files_in_archive:
|
||||||
tar.extract('info.json', path=info_dir)
|
tar.extract('info.json', path=info_dir)
|
||||||
elif "./info.json" in tar.getnames():
|
elif "./info.json" in files_in_archive:
|
||||||
tar.extract('./info.json', path=info_dir)
|
tar.extract('./info.json', path=info_dir)
|
||||||
else:
|
else:
|
||||||
raise KeyError
|
raise KeyError
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.debug("unable to retrieve '%s' inside the archive",
|
logger.debug("unable to retrieve '%s' inside the archive",
|
||||||
info_file, exc_info=1)
|
info_file, exc_info=1)
|
||||||
raise YunohostError('backup_invalid_archive')
|
raise YunohostError('backup_archive_cant_retrieve_info_json', archive=archive_file)
|
||||||
else:
|
else:
|
||||||
shutil.move(os.path.join(info_dir, 'info.json'), info_file)
|
shutil.move(os.path.join(info_dir, 'info.json'), info_file)
|
||||||
finally:
|
finally:
|
||||||
|
@ -2348,7 +2359,7 @@ def backup_info(name, with_details=False, human_readable=False):
|
||||||
info = json.load(f)
|
info = json.load(f)
|
||||||
except:
|
except:
|
||||||
logger.debug("unable to load '%s'", info_file, exc_info=1)
|
logger.debug("unable to load '%s'", info_file, exc_info=1)
|
||||||
raise YunohostError('backup_invalid_archive')
|
raise YunohostError('backup_archive_cant_retrieve_info_json', archive=archive_file)
|
||||||
|
|
||||||
# Retrieve backup size
|
# Retrieve backup size
|
||||||
size = info.get('size', 0)
|
size = info.get('size', 0)
|
||||||
|
|
|
@ -34,15 +34,14 @@ import glob
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from yunohost.vendor.acme_tiny.acme_tiny import get_crt as sign_certificate
|
from moulinette import m18n
|
||||||
|
|
||||||
from yunohost.utils.error import YunohostError
|
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
|
from moulinette.utils.filesystem import read_file
|
||||||
|
|
||||||
|
from yunohost.vendor.acme_tiny.acme_tiny import get_crt as sign_certificate
|
||||||
|
from yunohost.utils.error import YunohostError
|
||||||
from yunohost.utils.network import get_public_ip
|
from yunohost.utils.network import get_public_ip
|
||||||
|
|
||||||
from moulinette import m18n
|
|
||||||
from yunohost.app import app_ssowatconf
|
|
||||||
from yunohost.service import _run_service_command
|
from yunohost.service import _run_service_command
|
||||||
from yunohost.regenconf import regen_conf
|
from yunohost.regenconf import regen_conf
|
||||||
from yunohost.log import OperationLogger
|
from yunohost.log import OperationLogger
|
||||||
|
@ -468,14 +467,15 @@ Subject: %s
|
||||||
|
|
||||||
|
|
||||||
def _check_acme_challenge_configuration(domain):
|
def _check_acme_challenge_configuration(domain):
|
||||||
# Check nginx conf file exists
|
|
||||||
nginx_conf_folder = "/etc/nginx/conf.d/%s.d" % domain
|
|
||||||
nginx_conf_file = "%s/000-acmechallenge.conf" % nginx_conf_folder
|
|
||||||
|
|
||||||
if not os.path.exists(nginx_conf_file):
|
domain_conf = "/etc/nginx/conf.d/%s.conf" % domain
|
||||||
return False
|
if "include /etc/nginx/conf.d/acme-challenge.conf.inc" in read_file(domain_conf):
|
||||||
else:
|
|
||||||
return True
|
return True
|
||||||
|
else:
|
||||||
|
# This is for legacy setups which haven't updated their domain conf to
|
||||||
|
# the new conf that include the acme snippet...
|
||||||
|
legacy_acme_conf = "/etc/nginx/conf.d/%s.d/000-acmechallenge.conf" % domain
|
||||||
|
return os.path.exists(legacy_acme_conf)
|
||||||
|
|
||||||
|
|
||||||
def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False):
|
def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False):
|
||||||
|
@ -592,9 +592,9 @@ def _prepare_certificate_signing_request(domain, key_file, output_folder):
|
||||||
# Set the domain
|
# Set the domain
|
||||||
csr.get_subject().CN = domain
|
csr.get_subject().CN = domain
|
||||||
|
|
||||||
from yunohost.domain import _get_maindomain
|
from yunohost.domain import domain_list
|
||||||
if domain == _get_maindomain():
|
# For "parent" domains, include xmpp-upload subdomain in subject alternate names
|
||||||
# Include xmpp-upload subdomain in subject alternate names
|
if domain in domain_list(exclude_subdomains=True)["domains"]:
|
||||||
subdomain = "xmpp-upload." + domain
|
subdomain = "xmpp-upload." + domain
|
||||||
try:
|
try:
|
||||||
_dns_ip_match_public_ip(get_public_ip(), subdomain)
|
_dns_ip_match_public_ip(get_public_ip(), subdomain)
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
Look for possible issues on the server
|
Look for possible issues on the server
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
@ -38,14 +39,38 @@ logger = log.getActionLogger('yunohost.diagnosis')
|
||||||
|
|
||||||
DIAGNOSIS_CACHE = "/var/cache/yunohost/diagnosis/"
|
DIAGNOSIS_CACHE = "/var/cache/yunohost/diagnosis/"
|
||||||
DIAGNOSIS_CONFIG_FILE = '/etc/yunohost/diagnosis.yml'
|
DIAGNOSIS_CONFIG_FILE = '/etc/yunohost/diagnosis.yml'
|
||||||
|
DIAGNOSIS_SERVER = "diagnosis.yunohost.org"
|
||||||
|
|
||||||
def diagnosis_list():
|
def diagnosis_list():
|
||||||
all_categories_names = [h for h, _ in _list_diagnosis_categories()]
|
all_categories_names = [h for h, _ in _list_diagnosis_categories()]
|
||||||
return {"categories": all_categories_names}
|
return {"categories": all_categories_names}
|
||||||
|
|
||||||
|
|
||||||
|
def diagnosis_get(category, item):
|
||||||
|
|
||||||
|
# Get all the categories
|
||||||
|
all_categories = _list_diagnosis_categories()
|
||||||
|
all_categories_names = [c for c, _ in all_categories]
|
||||||
|
|
||||||
|
if category not in all_categories_names:
|
||||||
|
raise YunohostError('diagnosis_unknown_categories', categories=category)
|
||||||
|
|
||||||
|
if isinstance(item, list):
|
||||||
|
if any("=" not in criteria for criteria in item):
|
||||||
|
raise YunohostError("Criterias should be of the form key=value (e.g. domain=yolo.test)")
|
||||||
|
|
||||||
|
# Convert the provided criteria into a nice dict
|
||||||
|
item = {c.split("=")[0]: c.split("=")[1] for c in item}
|
||||||
|
|
||||||
|
return Diagnoser.get_cached_report(category, item=item)
|
||||||
|
|
||||||
|
|
||||||
def diagnosis_show(categories=[], issues=False, full=False, share=False):
|
def diagnosis_show(categories=[], issues=False, full=False, share=False):
|
||||||
|
|
||||||
|
if not os.path.exists(DIAGNOSIS_CACHE):
|
||||||
|
logger.warning(m18n.n("diagnosis_never_ran_yet"))
|
||||||
|
return
|
||||||
|
|
||||||
# Get all the categories
|
# Get all the categories
|
||||||
all_categories = _list_diagnosis_categories()
|
all_categories = _list_diagnosis_categories()
|
||||||
all_categories_names = [category for category, _ in all_categories]
|
all_categories_names = [category for category, _ in all_categories]
|
||||||
|
@ -56,29 +81,20 @@ def diagnosis_show(categories=[], issues=False, full=False, share=False):
|
||||||
else:
|
else:
|
||||||
unknown_categories = [c for c in categories if c not in all_categories_names]
|
unknown_categories = [c for c in categories if c not in all_categories_names]
|
||||||
if unknown_categories:
|
if unknown_categories:
|
||||||
raise YunohostError('diagnosis_unknown_categories', categories=", ".join(categories))
|
raise YunohostError('diagnosis_unknown_categories', categories=", ".join(unknown_categories))
|
||||||
|
|
||||||
if not os.path.exists(DIAGNOSIS_CACHE):
|
|
||||||
logger.warning(m18n.n("diagnosis_never_ran_yet"))
|
|
||||||
return
|
|
||||||
|
|
||||||
# Fetch all reports
|
# Fetch all reports
|
||||||
all_reports = []
|
all_reports = []
|
||||||
for category in categories:
|
for category in categories:
|
||||||
if not os.path.exists(Diagnoser.cache_file(category)):
|
|
||||||
logger.warning(m18n.n("diagnosis_no_cache", category=category))
|
|
||||||
report = {"id": category,
|
|
||||||
"cached_for": -1,
|
|
||||||
"timestamp": -1,
|
|
||||||
"items": []}
|
|
||||||
Diagnoser.i18n(report)
|
|
||||||
else:
|
|
||||||
try:
|
try:
|
||||||
report = Diagnoser.get_cached_report(category)
|
report = Diagnoser.get_cached_report(category)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(m18n.n("diagnosis_failed", category=category, error=str(e)))
|
logger.error(m18n.n("diagnosis_failed", category=category, error=str(e)))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
Diagnoser.i18n(report)
|
||||||
|
|
||||||
add_ignore_flag_to_issues(report)
|
add_ignore_flag_to_issues(report)
|
||||||
if not full:
|
if not full:
|
||||||
del report["timestamp"]
|
del report["timestamp"]
|
||||||
|
@ -128,7 +144,10 @@ def _dump_human_readable_reports(reports):
|
||||||
return(output)
|
return(output)
|
||||||
|
|
||||||
|
|
||||||
def diagnosis_run(categories=[], force=False):
|
def diagnosis_run(categories=[], force=False, except_if_never_ran_yet=False):
|
||||||
|
|
||||||
|
if except_if_never_ran_yet and not os.path.exists(DIAGNOSIS_CACHE):
|
||||||
|
return
|
||||||
|
|
||||||
# Get all the categories
|
# Get all the categories
|
||||||
all_categories = _list_diagnosis_categories()
|
all_categories = _list_diagnosis_categories()
|
||||||
|
@ -152,17 +171,15 @@ def diagnosis_run(categories=[], force=False):
|
||||||
try:
|
try:
|
||||||
code, report = hook_exec(path, args={"force": force}, env=None)
|
code, report = hook_exec(path, args={"force": force}, env=None)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(m18n.n("diagnosis_failed_for_category", category=category, error=str(e)), exc_info=True)
|
import traceback
|
||||||
|
logger.error(m18n.n("diagnosis_failed_for_category", category=category, error='\n'+traceback.format_exc()))
|
||||||
else:
|
else:
|
||||||
diagnosed_categories.append(category)
|
diagnosed_categories.append(category)
|
||||||
if report != {}:
|
if report != {}:
|
||||||
issues.extend([item for item in report["items"] if item["status"] in ["WARNING", "ERROR"]])
|
issues.extend([item for item in report["items"] if item["status"] in ["WARNING", "ERROR"]])
|
||||||
|
|
||||||
if issues:
|
if issues and msettings.get("interface") == "cli":
|
||||||
if msettings.get("interface") == "api":
|
logger.warning(m18n.n("diagnosis_display_tip"))
|
||||||
logger.info(m18n.n("diagnosis_display_tip_web"))
|
|
||||||
else:
|
|
||||||
logger.info(m18n.n("diagnosis_display_tip_cli"))
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -221,7 +238,7 @@ def diagnosis_ignore(add_filter=None, remove_filter=None, list=False):
|
||||||
if category not in all_categories_names:
|
if category not in all_categories_names:
|
||||||
raise YunohostError("%s is not a diagnosis category" % category)
|
raise YunohostError("%s is not a diagnosis category" % category)
|
||||||
if any("=" not in criteria for criteria in filter_[1:]):
|
if any("=" not in criteria for criteria in filter_[1:]):
|
||||||
raise YunohostError("Extra criterias should be of the form key=value (e.g. domain=yolo.test)")
|
raise YunohostError("Criterias should be of the form key=value (e.g. domain=yolo.test)")
|
||||||
|
|
||||||
# Convert the provided criteria into a nice dict
|
# Convert the provided criteria into a nice dict
|
||||||
criterias = {c.split("=")[0]: c.split("=")[1] for c in filter_[1:]}
|
criterias = {c.split("=")[0]: c.split("=")[1] for c in filter_[1:]}
|
||||||
|
@ -356,15 +373,22 @@ class Diagnoser():
|
||||||
|
|
||||||
for dependency in self.dependencies:
|
for dependency in self.dependencies:
|
||||||
dep_report = Diagnoser.get_cached_report(dependency)
|
dep_report = Diagnoser.get_cached_report(dependency)
|
||||||
|
|
||||||
|
if dep_report["timestamp"] == -1: # No cache yet for this dep
|
||||||
|
dep_errors = True
|
||||||
|
else:
|
||||||
dep_errors = [item for item in dep_report["items"] if item["status"] == "ERROR"]
|
dep_errors = [item for item in dep_report["items"] if item["status"] == "ERROR"]
|
||||||
|
|
||||||
if dep_errors:
|
if dep_errors:
|
||||||
logger.error(m18n.n("diagnosis_cant_run_because_of_dep", category=self.description, dep=Diagnoser.get_description(dependency)))
|
logger.error(m18n.n("diagnosis_cant_run_because_of_dep", category=self.description, dep=Diagnoser.get_description(dependency)))
|
||||||
return 1, {}
|
return 1, {}
|
||||||
|
|
||||||
self.logger_debug("Running diagnostic for %s" % self.id_)
|
|
||||||
|
|
||||||
items = list(self.run())
|
items = list(self.run())
|
||||||
|
|
||||||
|
for item in items:
|
||||||
|
if "details" in item and not item["details"]:
|
||||||
|
del item["details"]
|
||||||
|
|
||||||
new_report = {"id": self.id_,
|
new_report = {"id": self.id_,
|
||||||
"cached_for": self.cache_duration,
|
"cached_for": self.cache_duration,
|
||||||
"items": items}
|
"items": items}
|
||||||
|
@ -396,11 +420,24 @@ class Diagnoser():
|
||||||
return os.path.join(DIAGNOSIS_CACHE, "%s.json" % id_)
|
return os.path.join(DIAGNOSIS_CACHE, "%s.json" % id_)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_cached_report(id_):
|
def get_cached_report(id_, item=None):
|
||||||
filename = Diagnoser.cache_file(id_)
|
cache_file = Diagnoser.cache_file(id_)
|
||||||
report = read_json(filename)
|
if not os.path.exists(cache_file):
|
||||||
report["timestamp"] = int(os.path.getmtime(filename))
|
logger.warning(m18n.n("diagnosis_no_cache", category=id_))
|
||||||
Diagnoser.i18n(report)
|
report = {"id": id_,
|
||||||
|
"cached_for": -1,
|
||||||
|
"timestamp": -1,
|
||||||
|
"items": []}
|
||||||
|
else:
|
||||||
|
report = read_json(cache_file)
|
||||||
|
report["timestamp"] = int(os.path.getmtime(cache_file))
|
||||||
|
|
||||||
|
if item:
|
||||||
|
for report_item in report["items"]:
|
||||||
|
if report_item.get("meta") == item:
|
||||||
|
return report_item
|
||||||
|
return {}
|
||||||
|
else:
|
||||||
return report
|
return report
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -422,11 +459,84 @@ class Diagnoser():
|
||||||
report["description"] = Diagnoser.get_description(report["id"])
|
report["description"] = Diagnoser.get_description(report["id"])
|
||||||
|
|
||||||
for item in report["items"]:
|
for item in report["items"]:
|
||||||
summary_key, summary_args = item["summary"]
|
|
||||||
item["summary"] = m18n.n(summary_key, **summary_args)
|
# For the summary and each details, we want to call
|
||||||
|
# m18n() on the string, with the appropriate data for string
|
||||||
|
# formatting which can come from :
|
||||||
|
# - infos super-specific to the summary/details (if it's a tuple(key,dict_with_info) and not just a string)
|
||||||
|
# - 'meta' info = parameters of the test (e.g. which domain/category for DNS conf record)
|
||||||
|
# - actual 'data' retrieved from the test (e.g. actual global IP, ...)
|
||||||
|
|
||||||
|
meta_data = item.get("meta", {}).copy()
|
||||||
|
meta_data.update(item.get("data", {}))
|
||||||
|
|
||||||
|
html_tags = re.compile(r'<[^>]+>')
|
||||||
|
def m18n_(info):
|
||||||
|
if not isinstance(info, tuple) and not isinstance(info, list):
|
||||||
|
info = (info, {})
|
||||||
|
info[1].update(meta_data)
|
||||||
|
s = m18n.n(info[0], **(info[1]))
|
||||||
|
# In cli, we remove the html tags
|
||||||
|
if msettings.get("interface") != "api":
|
||||||
|
s = s.replace("<cmd>", "'").replace("</cmd>", "'")
|
||||||
|
s = html_tags.sub('', s.replace("<br>","\n"))
|
||||||
|
else:
|
||||||
|
s = s.replace("<cmd>", "<code class='cmd'>").replace("</cmd>", "</code>")
|
||||||
|
# Make it so that links open in new tabs
|
||||||
|
s = s.replace("<a href=", "<a target='_blank' rel='noopener noreferrer' href=")
|
||||||
|
return s
|
||||||
|
|
||||||
|
item["summary"] = m18n_(item["summary"])
|
||||||
|
|
||||||
if "details" in item:
|
if "details" in item:
|
||||||
item["details"] = [m18n.n(key, *values) for key, values in item["details"]]
|
item["details"] = [m18n_(info) for info in item["details"]]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def remote_diagnosis(uri, data, ipversion, timeout=30):
|
||||||
|
|
||||||
|
# Lazy loading for performance
|
||||||
|
import requests
|
||||||
|
import socket
|
||||||
|
|
||||||
|
# Monkey patch socket.getaddrinfo to force request() to happen in ipv4
|
||||||
|
# or 6 ...
|
||||||
|
# Inspired by https://stackoverflow.com/a/50044152
|
||||||
|
old_getaddrinfo = socket.getaddrinfo
|
||||||
|
|
||||||
|
def getaddrinfo_ipv4_only(*args, **kwargs):
|
||||||
|
responses = old_getaddrinfo(*args, **kwargs)
|
||||||
|
return [response
|
||||||
|
for response in responses
|
||||||
|
if response[0] == socket.AF_INET]
|
||||||
|
|
||||||
|
def getaddrinfo_ipv6_only(*args, **kwargs):
|
||||||
|
responses = old_getaddrinfo(*args, **kwargs)
|
||||||
|
return [response
|
||||||
|
for response in responses
|
||||||
|
if response[0] == socket.AF_INET6]
|
||||||
|
|
||||||
|
if ipversion == 4:
|
||||||
|
socket.getaddrinfo = getaddrinfo_ipv4_only
|
||||||
|
elif ipversion == 6:
|
||||||
|
socket.getaddrinfo = getaddrinfo_ipv6_only
|
||||||
|
|
||||||
|
url = 'https://%s/%s' % (DIAGNOSIS_SERVER, uri)
|
||||||
|
try:
|
||||||
|
r = requests.post(url, json=data, timeout=timeout)
|
||||||
|
finally:
|
||||||
|
socket.getaddrinfo = old_getaddrinfo
|
||||||
|
|
||||||
|
if r.status_code not in [200, 400]:
|
||||||
|
raise Exception("The remote diagnosis server failed miserably while trying to diagnose your server. This is most likely an error on Yunohost's infrastructure and not on your side. Please contact the YunoHost team an provide them with the following information.<br>URL: <code>%s</code><br>Status code: <code>%s</code>" % (url, r.status_code))
|
||||||
|
if r.status_code == 400:
|
||||||
|
raise Exception("Diagnosis request was refused: %s" % r.content)
|
||||||
|
|
||||||
|
try:
|
||||||
|
r = r.json()
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception("Failed to parse json from diagnosis server response.\nError: %s\nOriginal content: %s" % (e, r.content))
|
||||||
|
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
def _list_diagnosis_categories():
|
def _list_diagnosis_categories():
|
||||||
|
|
|
@ -33,7 +33,7 @@ from yunohost.utils.error import YunohostError
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
|
|
||||||
from yunohost.app import app_ssowatconf
|
from yunohost.app import app_ssowatconf
|
||||||
from yunohost.regenconf import regen_conf
|
from yunohost.regenconf import regen_conf, _force_clear_hashes, _process_regen_conf
|
||||||
from yunohost.utils.network import get_public_ip
|
from yunohost.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
|
from yunohost.hook import hook_callback
|
||||||
|
@ -41,24 +41,26 @@ from yunohost.hook import hook_callback
|
||||||
logger = getActionLogger('yunohost.domain')
|
logger = getActionLogger('yunohost.domain')
|
||||||
|
|
||||||
|
|
||||||
def domain_list():
|
def domain_list(exclude_subdomains=False):
|
||||||
"""
|
"""
|
||||||
List domains
|
List domains
|
||||||
|
|
||||||
Keyword argument:
|
Keyword argument:
|
||||||
filter -- LDAP filter used to search
|
exclude_subdomains -- Filter out domains that are subdomains of other declared domains
|
||||||
offset -- Starting number for domain fetching
|
|
||||||
limit -- Maximum number of domain fetched
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from yunohost.utils.ldap import _get_ldap_interface
|
from yunohost.utils.ldap import _get_ldap_interface
|
||||||
|
|
||||||
ldap = _get_ldap_interface()
|
ldap = _get_ldap_interface()
|
||||||
result = ldap.search('ou=domains,dc=yunohost,dc=org', 'virtualdomain=*', ['virtualdomain'])
|
result = [entry['virtualdomain'][0] for entry in ldap.search('ou=domains,dc=yunohost,dc=org', 'virtualdomain=*', ['virtualdomain'])]
|
||||||
|
|
||||||
result_list = []
|
result_list = []
|
||||||
for domain in result:
|
for domain in result:
|
||||||
result_list.append(domain['virtualdomain'][0])
|
if exclude_subdomains:
|
||||||
|
parent_domain = domain.split(".", 1)[1]
|
||||||
|
if parent_domain in result:
|
||||||
|
continue
|
||||||
|
result_list.append(domain)
|
||||||
|
|
||||||
return {'domains': result_list}
|
return {'domains': result_list}
|
||||||
|
|
||||||
|
@ -122,6 +124,17 @@ def domain_add(operation_logger, 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'):
|
||||||
|
# Sometime we have weird issues with the regenconf where some files
|
||||||
|
# appears as manually modified even though they weren't touched ...
|
||||||
|
# There are a few ideas why this happens (like backup/restore nginx
|
||||||
|
# conf ... which we shouldnt do ...). This in turns creates funky
|
||||||
|
# situation where the regenconf may refuse to re-create the conf
|
||||||
|
# (when re-creating a domain..)
|
||||||
|
# So here we force-clear the has out of the regenconf if it exists.
|
||||||
|
# This is a pretty ad hoc solution and only applied to nginx
|
||||||
|
# because it's one of the major service, but in the long term we
|
||||||
|
# should identify the root of this bug...
|
||||||
|
_force_clear_hashes(["/etc/nginx/conf.d/%s.conf" % domain])
|
||||||
regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix', 'rspamd'])
|
regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix', 'rspamd'])
|
||||||
app_ssowatconf()
|
app_ssowatconf()
|
||||||
|
|
||||||
|
@ -186,6 +199,25 @@ def domain_remove(operation_logger, domain, force=False):
|
||||||
|
|
||||||
os.system('rm -rf /etc/yunohost/certs/%s' % domain)
|
os.system('rm -rf /etc/yunohost/certs/%s' % domain)
|
||||||
|
|
||||||
|
# Sometime we have weird issues with the regenconf where some files
|
||||||
|
# appears as manually modified even though they weren't touched ...
|
||||||
|
# There are a few ideas why this happens (like backup/restore nginx
|
||||||
|
# conf ... which we shouldnt do ...). This in turns creates funky
|
||||||
|
# situation where the regenconf may refuse to re-create the conf
|
||||||
|
# (when re-creating a domain..)
|
||||||
|
#
|
||||||
|
# So here we force-clear the has out of the regenconf if it exists.
|
||||||
|
# This is a pretty ad hoc solution and only applied to nginx
|
||||||
|
# because it's one of the major service, but in the long term we
|
||||||
|
# should identify the root of this bug...
|
||||||
|
_force_clear_hashes(["/etc/nginx/conf.d/%s.conf" % domain])
|
||||||
|
# And in addition we even force-delete the file Otherwise, if the file was
|
||||||
|
# manually modified, it may not get removed by the regenconf which leads to
|
||||||
|
# catastrophic consequences of nginx breaking because it can't load the
|
||||||
|
# cert file which disappeared etc..
|
||||||
|
if os.path.exists("/etc/nginx/conf.d/%s.conf" % domain):
|
||||||
|
_process_regen_conf("/etc/nginx/conf.d/%s.conf" % domain, new_conf=None, save=True)
|
||||||
|
|
||||||
regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix'])
|
regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix'])
|
||||||
app_ssowatconf()
|
app_ssowatconf()
|
||||||
|
|
||||||
|
@ -395,7 +427,7 @@ def _normalize_domain_path(domain, path):
|
||||||
return domain, path
|
return domain, path
|
||||||
|
|
||||||
|
|
||||||
def _build_dns_conf(domain, ttl=3600):
|
def _build_dns_conf(domain, ttl=3600, include_empty_AAAA_if_no_ipv6=False):
|
||||||
"""
|
"""
|
||||||
Internal function that will returns a data structure containing the needed
|
Internal function that will returns a data structure containing the needed
|
||||||
information to generate/adapt the dns configuration
|
information to generate/adapt the dns configuration
|
||||||
|
@ -448,21 +480,16 @@ def _build_dns_conf(domain, ttl=3600):
|
||||||
|
|
||||||
if ipv6:
|
if ipv6:
|
||||||
basic.append(["@", ttl, "AAAA", ipv6])
|
basic.append(["@", ttl, "AAAA", ipv6])
|
||||||
|
elif include_empty_AAAA_if_no_ipv6:
|
||||||
|
basic.append(["@", ttl, "AAAA", None])
|
||||||
|
|
||||||
#########
|
#########
|
||||||
# Email #
|
# Email #
|
||||||
#########
|
#########
|
||||||
|
|
||||||
spf_record = '"v=spf1 a mx'
|
|
||||||
if ipv4:
|
|
||||||
spf_record += ' ip4:{ip4}'.format(ip4=ipv4)
|
|
||||||
if ipv6:
|
|
||||||
spf_record += ' ip6:{ip6}'.format(ip6=ipv6)
|
|
||||||
spf_record += ' -all"'
|
|
||||||
|
|
||||||
mail = [
|
mail = [
|
||||||
["@", ttl, "MX", "10 %s." % domain],
|
["@", ttl, "MX", "10 %s." % domain],
|
||||||
["@", ttl, "TXT", spf_record],
|
["@", ttl, "TXT", '"v=spf1 a mx -all"'],
|
||||||
]
|
]
|
||||||
|
|
||||||
# DKIM/DMARC record
|
# DKIM/DMARC record
|
||||||
|
@ -495,8 +522,11 @@ def _build_dns_conf(domain, ttl=3600):
|
||||||
|
|
||||||
if ipv4:
|
if ipv4:
|
||||||
extra.append(["*", ttl, "A", ipv4])
|
extra.append(["*", ttl, "A", ipv4])
|
||||||
|
|
||||||
if ipv6:
|
if ipv6:
|
||||||
extra.append(["*", ttl, "AAAA", ipv6])
|
extra.append(["*", ttl, "AAAA", ipv6])
|
||||||
|
elif include_empty_AAAA_if_no_ipv6:
|
||||||
|
extra.append(["*", ttl, "AAAA", None])
|
||||||
|
|
||||||
extra.append(["@", ttl, "CAA", '128 issue "letsencrypt.org"'])
|
extra.append(["@", ttl, "CAA", '128 issue "letsencrypt.org"'])
|
||||||
|
|
||||||
|
|
|
@ -259,11 +259,6 @@ def dyndns_update(operation_logger, dyn_host="dyndns.yunohost.org", domain=None,
|
||||||
|
|
||||||
dns_conf = _build_dns_conf(domain)
|
dns_conf = _build_dns_conf(domain)
|
||||||
|
|
||||||
for i, record in enumerate(dns_conf["extra"]):
|
|
||||||
# Ignore CAA record ... not sure why, we could probably enforce it...
|
|
||||||
if record[3] == "CAA":
|
|
||||||
del dns_conf["extra"][i]
|
|
||||||
|
|
||||||
# Delete custom DNS records, we don't support them (have to explicitly
|
# Delete custom DNS records, we don't support them (have to explicitly
|
||||||
# authorize them on dynette)
|
# authorize them on dynette)
|
||||||
for category in dns_conf.keys():
|
for category in dns_conf.keys():
|
||||||
|
|
|
@ -473,6 +473,18 @@ def _update_conf_hashes(category, hashes):
|
||||||
_save_regenconf_infos(categories)
|
_save_regenconf_infos(categories)
|
||||||
|
|
||||||
|
|
||||||
|
def _force_clear_hashes(paths):
|
||||||
|
|
||||||
|
categories = _get_regenconf_infos()
|
||||||
|
for path in paths:
|
||||||
|
for category in categories.keys():
|
||||||
|
if path in categories[category]['conffiles']:
|
||||||
|
logger.debug("force-clearing old conf hash for %s in category %s" % (path, category))
|
||||||
|
del categories[category]['conffiles'][path]
|
||||||
|
|
||||||
|
_save_regenconf_infos(categories)
|
||||||
|
|
||||||
|
|
||||||
def _process_regen_conf(system_conf, new_conf=None, save=True):
|
def _process_regen_conf(system_conf, new_conf=None, save=True):
|
||||||
"""Regenerate a given system configuration file
|
"""Regenerate a given system configuration file
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@ def service_add(name, description=None, log=None, log_type="file", test_status=N
|
||||||
services[name]['description'] = description
|
services[name]['description'] = description
|
||||||
else:
|
else:
|
||||||
# Try to get the description from systemd service
|
# Try to get the description from systemd service
|
||||||
out = subprocess.check_output("systemctl show %s | grep '^Description='" % name, shell=True)
|
out = subprocess.check_output("systemctl show %s | grep '^Description='" % name, shell=True).strip()
|
||||||
out = out.replace("Description=", "")
|
out = out.replace("Description=", "")
|
||||||
# If the service does not yet exists or if the description is empty,
|
# If the service does not yet exists or if the description is empty,
|
||||||
# systemd will anyway return foo.service as default value, so we wanna
|
# systemd will anyway return foo.service as default value, so we wanna
|
||||||
|
@ -295,16 +295,11 @@ def service_status(names=[]):
|
||||||
if services[name].get("status", "") is None:
|
if services[name].get("status", "") is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
status = _get_service_information_from_systemd(name)
|
systemd_service = services[name].get("actual_systemd_service", name)
|
||||||
|
status = _get_service_information_from_systemd(systemd_service)
|
||||||
# try to get status using alternative version if they exists
|
|
||||||
# this is for mariadb/mysql but is generic in case of
|
|
||||||
alternates = services[name].get("alternates", [])
|
|
||||||
while status is None and alternates:
|
|
||||||
status = _get_service_information_from_systemd(alternates.pop())
|
|
||||||
|
|
||||||
if status is None:
|
if status is None:
|
||||||
logger.error("Failed to get status information via dbus for service %s, systemctl didn't recognize this service ('NoSuchUnit')." % name)
|
logger.error("Failed to get status information via dbus for service %s, systemctl didn't recognize this service ('NoSuchUnit')." % systemd_service)
|
||||||
result[name] = {
|
result[name] = {
|
||||||
'status': "unknown",
|
'status': "unknown",
|
||||||
'start_on_boot': "unknown",
|
'start_on_boot': "unknown",
|
||||||
|
@ -338,6 +333,8 @@ def service_status(names=[]):
|
||||||
# gotta do this ... cf code of /lib/systemd/systemd-sysv-install
|
# gotta do this ... cf code of /lib/systemd/systemd-sysv-install
|
||||||
if result[name]["start_on_boot"] == "generated":
|
if result[name]["start_on_boot"] == "generated":
|
||||||
result[name]["start_on_boot"] = "enabled" if glob("/etc/rc[S5].d/S??"+name) else "disabled"
|
result[name]["start_on_boot"] = "enabled" if glob("/etc/rc[S5].d/S??"+name) else "disabled"
|
||||||
|
elif os.path.exists("/etc/systemd/system/multi-user.target.wants/%s.service" % name):
|
||||||
|
result[name]["start_on_boot"] = "enabled"
|
||||||
|
|
||||||
if "StateChangeTimestamp" in status:
|
if "StateChangeTimestamp" in status:
|
||||||
result[name]['last_state_change'] = datetime.utcfromtimestamp(status["StateChangeTimestamp"] / 1000000)
|
result[name]['last_state_change'] = datetime.utcfromtimestamp(status["StateChangeTimestamp"] / 1000000)
|
||||||
|
@ -408,6 +405,7 @@ def service_log(name, number=50):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
services = _get_services()
|
services = _get_services()
|
||||||
|
number = int(number)
|
||||||
|
|
||||||
if name not in services.keys():
|
if name not in services.keys():
|
||||||
raise YunohostError('service_unknown', service=name)
|
raise YunohostError('service_unknown', service=name)
|
||||||
|
@ -423,11 +421,7 @@ def service_log(name, number=50):
|
||||||
result = {}
|
result = {}
|
||||||
|
|
||||||
# First we always add the logs from journalctl / systemd
|
# First we always add the logs from journalctl / systemd
|
||||||
result["journalctl"] = _get_journalctl_logs(name, int(number)).splitlines()
|
result["journalctl"] = _get_journalctl_logs(name, number).splitlines()
|
||||||
|
|
||||||
# Mysql and journalctl are fucking annoying, we gotta explictly fetch mariadb ...
|
|
||||||
if name == "mysql":
|
|
||||||
result["journalctl"] = _get_journalctl_logs("mariadb", int(number)).splitlines()
|
|
||||||
|
|
||||||
for index, log_path in enumerate(log_list):
|
for index, log_path in enumerate(log_list):
|
||||||
log_type = log_type_list[index]
|
log_type = log_type_list[index]
|
||||||
|
@ -435,7 +429,7 @@ def service_log(name, number=50):
|
||||||
if log_type == "file":
|
if log_type == "file":
|
||||||
# log is a file, read it
|
# log is a file, read it
|
||||||
if not os.path.isdir(log_path):
|
if not os.path.isdir(log_path):
|
||||||
result[log_path] = _tail(log_path, int(number)) if os.path.exists(log_path) else []
|
result[log_path] = _tail(log_path, number) if os.path.exists(log_path) else []
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for log_file in os.listdir(log_path):
|
for log_file in os.listdir(log_path):
|
||||||
|
@ -447,10 +441,11 @@ def service_log(name, number=50):
|
||||||
if not log_file.endswith(".log"):
|
if not log_file.endswith(".log"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
result[log_file_path] = _tail(log_file_path, int(number)) if os.path.exists(log_file_path) else []
|
result[log_file_path] = _tail(log_file_path, number) if os.path.exists(log_file_path) else []
|
||||||
else:
|
else:
|
||||||
|
# N.B. : this is legacy code that can probably be removed ... to be confirmed
|
||||||
# get log with journalctl
|
# get log with journalctl
|
||||||
result[log_path] = _get_journalctl_logs(log_path, int(number)).splitlines()
|
result[log_path] = _get_journalctl_logs(log_path, number).splitlines()
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -572,13 +567,21 @@ def _get_services():
|
||||||
services = yaml.load(f)
|
services = yaml.load(f)
|
||||||
except:
|
except:
|
||||||
return {}
|
return {}
|
||||||
else:
|
|
||||||
# some services are marked as None to remove them from YunoHost
|
# some services are marked as None to remove them from YunoHost
|
||||||
# filter this
|
# filter this
|
||||||
for key, value in services.items():
|
for key, value in services.items():
|
||||||
if value is None:
|
if value is None:
|
||||||
del services[key]
|
del services[key]
|
||||||
|
|
||||||
|
# Stupid hack for postgresql which ain't an official service ... Can't
|
||||||
|
# really inject that info otherwise. Real service we want to check for
|
||||||
|
# status and log is in fact postgresql@x.y-main (x.y being the version)
|
||||||
|
if "postgresql" in services:
|
||||||
|
if "description" in services["postgresql"]:
|
||||||
|
del services["postgresql"]["description"]
|
||||||
|
services["postgresql"]["actual_systemd_service"] = "postgresql@9.6-main"
|
||||||
|
|
||||||
return services
|
return services
|
||||||
|
|
||||||
|
|
||||||
|
@ -674,8 +677,10 @@ def _find_previous_log_file(file):
|
||||||
|
|
||||||
|
|
||||||
def _get_journalctl_logs(service, number="all"):
|
def _get_journalctl_logs(service, number="all"):
|
||||||
|
services = _get_services()
|
||||||
|
systemd_service = services.get(service, {}).get("actual_systemd_service", service)
|
||||||
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(systemd_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()
|
||||||
|
|
|
@ -70,6 +70,7 @@ DEFAULTS = OrderedDict([
|
||||||
("security.postfix.compatibility", {"type": "enum", "default": "intermediate",
|
("security.postfix.compatibility", {"type": "enum", "default": "intermediate",
|
||||||
"choices": ["intermediate", "modern"]}),
|
"choices": ["intermediate", "modern"]}),
|
||||||
("pop3.enabled", {"type": "bool", "default": False}),
|
("pop3.enabled", {"type": "bool", "default": False}),
|
||||||
|
("smtp.allow_ipv6", {"type": "bool", "default": True}),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
@ -320,6 +321,7 @@ def reconfigure_ssh(setting_name, old_value, new_value):
|
||||||
if old_value != new_value:
|
if old_value != new_value:
|
||||||
service_regen_conf(names=['ssh'])
|
service_regen_conf(names=['ssh'])
|
||||||
|
|
||||||
|
@post_change_hook("smtp.allow_ipv6")
|
||||||
@post_change_hook("security.postfix.compatibility")
|
@post_change_hook("security.postfix.compatibility")
|
||||||
def reconfigure_postfix(setting_name, old_value, new_value):
|
def reconfigure_postfix(setting_name, old_value, new_value):
|
||||||
if old_value != new_value:
|
if old_value != new_value:
|
||||||
|
|
|
@ -9,7 +9,7 @@ from conftest import message, raiseYunohostError
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from moulinette.utils.filesystem import mkdir
|
from moulinette.utils.filesystem import mkdir
|
||||||
|
|
||||||
from yunohost.app import app_install, app_remove, app_ssowatconf, _is_installed, app_upgrade
|
from yunohost.app import app_install, app_remove, app_ssowatconf, _is_installed, app_upgrade, app_map
|
||||||
from yunohost.domain import _get_maindomain, domain_add, domain_remove, domain_list
|
from yunohost.domain import _get_maindomain, domain_add, domain_remove, domain_list
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError
|
||||||
from yunohost.tests.test_permission import check_LDAP_db_integrity, check_permission_for_apps
|
from yunohost.tests.test_permission import check_LDAP_db_integrity, check_permission_for_apps
|
||||||
|
@ -142,6 +142,12 @@ def test_legacy_app_install_main_domain():
|
||||||
|
|
||||||
install_legacy_app(main_domain, "/legacy")
|
install_legacy_app(main_domain, "/legacy")
|
||||||
|
|
||||||
|
app_map_ = app_map(raw=True)
|
||||||
|
assert main_domain in app_map_
|
||||||
|
assert '/legacy' in app_map_[main_domain]
|
||||||
|
assert 'id' in app_map_[main_domain]['/legacy']
|
||||||
|
assert app_map_[main_domain]['/legacy']['id'] == 'legacy_app'
|
||||||
|
|
||||||
assert app_is_installed(main_domain, "legacy_app")
|
assert app_is_installed(main_domain, "legacy_app")
|
||||||
assert app_is_exposed_on_http(main_domain, "/legacy", "This is a dummy app")
|
assert app_is_exposed_on_http(main_domain, "/legacy", "This is a dummy app")
|
||||||
|
|
||||||
|
@ -166,6 +172,12 @@ def test_legacy_app_install_secondary_domain_on_root(secondary_domain):
|
||||||
|
|
||||||
install_legacy_app(secondary_domain, "/")
|
install_legacy_app(secondary_domain, "/")
|
||||||
|
|
||||||
|
app_map_ = app_map(raw=True)
|
||||||
|
assert secondary_domain in app_map_
|
||||||
|
assert '/' in app_map_[secondary_domain]
|
||||||
|
assert 'id' in app_map_[secondary_domain]['/']
|
||||||
|
assert app_map_[secondary_domain]['/']['id'] == 'legacy_app'
|
||||||
|
|
||||||
assert app_is_installed(secondary_domain, "legacy_app")
|
assert app_is_installed(secondary_domain, "legacy_app")
|
||||||
assert app_is_exposed_on_http(secondary_domain, "/", "This is a dummy app")
|
assert app_is_exposed_on_http(secondary_domain, "/", "This is a dummy app")
|
||||||
|
|
||||||
|
|
|
@ -574,9 +574,22 @@ def test_restore_archive_with_no_json(mocker):
|
||||||
|
|
||||||
assert "badbackup" in backup_list()["archives"]
|
assert "badbackup" in backup_list()["archives"]
|
||||||
|
|
||||||
with raiseYunohostError(mocker, 'backup_invalid_archive'):
|
with raiseYunohostError(mocker, 'backup_archive_cant_retrieve_info_json'):
|
||||||
backup_restore(name="badbackup", force=True)
|
backup_restore(name="badbackup", force=True)
|
||||||
|
|
||||||
|
@pytest.mark.with_wordpress_archive_from_2p4
|
||||||
|
def test_restore_archive_with_bad_archive(mocker):
|
||||||
|
|
||||||
|
# Break the archive
|
||||||
|
os.system("head -n 1000 /home/yunohost.backup/archives/backup_wordpress_from_2p4.tar.gz > /home/yunohost.backup/archives/backup_wordpress_from_2p4.tar.gz")
|
||||||
|
|
||||||
|
assert "backup_wordpress_from_2p4" in backup_list()["archives"]
|
||||||
|
|
||||||
|
with raiseYunohostError(mocker, 'backup_archive_open_failed'):
|
||||||
|
backup_restore(name="backup_wordpress_from_2p4", force=True)
|
||||||
|
|
||||||
|
clean_tmp_backup_directory()
|
||||||
|
|
||||||
|
|
||||||
def test_backup_binds_are_readonly(mocker, monkeypatch):
|
def test_backup_binds_are_readonly(mocker, monkeypatch):
|
||||||
|
|
||||||
|
|
80
src/yunohost/tests/test_regenconf.py
Normal file
80
src/yunohost/tests/test_regenconf.py
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import pytest
|
||||||
|
import shutil
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from conftest import message, raiseYunohostError
|
||||||
|
|
||||||
|
from moulinette import m18n
|
||||||
|
from moulinette.utils.filesystem import mkdir
|
||||||
|
|
||||||
|
from yunohost.domain import _get_maindomain, domain_add, domain_remove, domain_list
|
||||||
|
from yunohost.utils.error import YunohostError
|
||||||
|
from yunohost.regenconf import manually_modified_files, _get_conf_hashes, _force_clear_hashes
|
||||||
|
|
||||||
|
TEST_DOMAIN = "secondarydomain.test"
|
||||||
|
TEST_DOMAIN_NGINX_CONFIG = "/etc/nginx/conf.d/secondarydomain.test.conf"
|
||||||
|
|
||||||
|
def setup_function(function):
|
||||||
|
|
||||||
|
_force_clear_hashes([TEST_DOMAIN_NGINX_CONFIG])
|
||||||
|
clean()
|
||||||
|
|
||||||
|
def teardown_function(function):
|
||||||
|
|
||||||
|
clean()
|
||||||
|
_force_clear_hashes([TEST_DOMAIN_NGINX_CONFIG])
|
||||||
|
|
||||||
|
def clean():
|
||||||
|
|
||||||
|
assert os.system("pgrep slapd >/dev/null") == 0
|
||||||
|
assert os.system("pgrep nginx >/dev/null") == 0
|
||||||
|
|
||||||
|
if TEST_DOMAIN in domain_list()["domains"]:
|
||||||
|
domain_remove(TEST_DOMAIN)
|
||||||
|
assert not os.path.exists(TEST_DOMAIN_NGINX_CONFIG)
|
||||||
|
|
||||||
|
os.system("rm -f %s" % TEST_DOMAIN_NGINX_CONFIG)
|
||||||
|
|
||||||
|
assert os.system("nginx -t 2>/dev/null") == 0
|
||||||
|
|
||||||
|
assert not os.path.exists(TEST_DOMAIN_NGINX_CONFIG)
|
||||||
|
assert TEST_DOMAIN_NGINX_CONFIG not in _get_conf_hashes("nginx")
|
||||||
|
assert TEST_DOMAIN_NGINX_CONFIG not in manually_modified_files()
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_domain():
|
||||||
|
|
||||||
|
domain_add(TEST_DOMAIN)
|
||||||
|
|
||||||
|
assert TEST_DOMAIN in domain_list()["domains"]
|
||||||
|
|
||||||
|
assert os.path.exists(TEST_DOMAIN_NGINX_CONFIG)
|
||||||
|
|
||||||
|
assert TEST_DOMAIN_NGINX_CONFIG in _get_conf_hashes("nginx")
|
||||||
|
assert TEST_DOMAIN_NGINX_CONFIG not in manually_modified_files()
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_and_edit_domain_conf():
|
||||||
|
|
||||||
|
domain_add(TEST_DOMAIN)
|
||||||
|
|
||||||
|
assert os.path.exists(TEST_DOMAIN_NGINX_CONFIG)
|
||||||
|
assert TEST_DOMAIN_NGINX_CONFIG in _get_conf_hashes("nginx")
|
||||||
|
assert TEST_DOMAIN_NGINX_CONFIG not in manually_modified_files()
|
||||||
|
|
||||||
|
os.system("echo ' ' >> %s" % TEST_DOMAIN_NGINX_CONFIG)
|
||||||
|
|
||||||
|
assert TEST_DOMAIN_NGINX_CONFIG in manually_modified_files()
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_domain_conf_already_exists():
|
||||||
|
|
||||||
|
os.system("echo ' ' >> %s" % TEST_DOMAIN_NGINX_CONFIG)
|
||||||
|
|
||||||
|
domain_add(TEST_DOMAIN)
|
||||||
|
|
||||||
|
assert os.path.exists(TEST_DOMAIN_NGINX_CONFIG)
|
||||||
|
assert TEST_DOMAIN_NGINX_CONFIG in _get_conf_hashes("nginx")
|
||||||
|
assert TEST_DOMAIN_NGINX_CONFIG not in manually_modified_files()
|
|
@ -18,10 +18,14 @@
|
||||||
along with this program; if not, see http://www.gnu.org/licenses
|
along with this program; if not, see http://www.gnu.org/licenses
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import logging
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import logging
|
||||||
|
import dns.resolver
|
||||||
|
|
||||||
from moulinette.utils.network import download_text
|
from moulinette.utils.network import download_text
|
||||||
|
from moulinette.utils.process import check_output
|
||||||
|
from moulinette.utils.filesystem import read_file
|
||||||
|
|
||||||
logger = logging.getLogger('yunohost.utils.network')
|
logger = logging.getLogger('yunohost.utils.network')
|
||||||
|
|
||||||
|
@ -36,6 +40,17 @@ def get_public_ip(protocol=4):
|
||||||
else:
|
else:
|
||||||
raise ValueError("invalid protocol version")
|
raise ValueError("invalid protocol version")
|
||||||
|
|
||||||
|
# We can know that ipv6 is not available directly if this file does not exists
|
||||||
|
if protocol == 6 and not os.path.exists("/proc/net/if_inet6"):
|
||||||
|
logger.debug("IPv6 appears not at all available on the system, so assuming there's no IP address for that version")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# If we are indeed connected in ipv4 or ipv6, we should find a default route
|
||||||
|
routes = check_output("ip -%s route" % protocol).split("\n")
|
||||||
|
if not any(r.startswith("default") for r in routes):
|
||||||
|
logger.debug("No default route for IPv%s, so assuming there's no IP address for that version" % protocol)
|
||||||
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return download_text(url, timeout=30).strip()
|
return download_text(url, timeout=30).strip()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -47,7 +62,7 @@ def get_network_interfaces():
|
||||||
|
|
||||||
# Get network devices and their addresses (raw infos from 'ip addr')
|
# Get network devices and their addresses (raw infos from 'ip addr')
|
||||||
devices_raw = {}
|
devices_raw = {}
|
||||||
output = subprocess.check_output('ip addr show'.split())
|
output = check_output('ip addr show')
|
||||||
for d in re.split(r'^(?:[0-9]+: )', output, flags=re.MULTILINE):
|
for d in re.split(r'^(?:[0-9]+: )', output, flags=re.MULTILINE):
|
||||||
# Extract device name (1) and its addresses (2)
|
# Extract device name (1) and its addresses (2)
|
||||||
m = re.match(r'([^\s@]+)(?:@[\S]+)?: (.*)', d, flags=re.DOTALL)
|
m = re.match(r'([^\s@]+)(?:@[\S]+)?: (.*)', d, flags=re.DOTALL)
|
||||||
|
@ -62,7 +77,7 @@ def get_network_interfaces():
|
||||||
|
|
||||||
def get_gateway():
|
def get_gateway():
|
||||||
|
|
||||||
output = subprocess.check_output('ip route show'.split())
|
output = check_output('ip route show')
|
||||||
m = re.search(r'default via (.*) dev ([a-z]+[0-9]?)', output)
|
m = re.search(r'default via (.*) dev ([a-z]+[0-9]?)', output)
|
||||||
if not m:
|
if not m:
|
||||||
return None
|
return None
|
||||||
|
@ -71,6 +86,52 @@ def get_gateway():
|
||||||
return addr.popitem()[1] if len(addr) == 1 else None
|
return addr.popitem()[1] if len(addr) == 1 else None
|
||||||
|
|
||||||
|
|
||||||
|
# Lazy dev caching to avoid re-reading the file multiple time when calling
|
||||||
|
# dig() often during same yunohost operation
|
||||||
|
external_resolvers_ = []
|
||||||
|
|
||||||
|
|
||||||
|
def external_resolvers():
|
||||||
|
|
||||||
|
global external_resolvers_
|
||||||
|
|
||||||
|
if not external_resolvers_:
|
||||||
|
resolv_dnsmasq_conf = read_file("/etc/resolv.dnsmasq.conf").split("\n")
|
||||||
|
external_resolvers_ = [r.split(" ")[1] for r in resolv_dnsmasq_conf if r.startswith("nameserver")]
|
||||||
|
|
||||||
|
return external_resolvers_
|
||||||
|
|
||||||
|
|
||||||
|
def dig(qname, rdtype="A", timeout=5, resolvers="local", edns_size=1500, full_answers=False):
|
||||||
|
"""
|
||||||
|
Do a quick DNS request and avoid the "search" trap inside /etc/resolv.conf
|
||||||
|
"""
|
||||||
|
|
||||||
|
if resolvers == "local":
|
||||||
|
resolvers = ["127.0.0.1"]
|
||||||
|
elif resolvers == "force_external":
|
||||||
|
resolvers = external_resolvers()
|
||||||
|
else:
|
||||||
|
assert isinstance(resolvers, list)
|
||||||
|
|
||||||
|
resolver = dns.resolver.Resolver(configure=False)
|
||||||
|
resolver.use_edns(0, 0, edns_size)
|
||||||
|
resolver.nameservers = resolvers
|
||||||
|
resolver.timeout = timeout
|
||||||
|
try:
|
||||||
|
answers = resolver.query(qname, rdtype)
|
||||||
|
except (dns.resolver.NXDOMAIN,
|
||||||
|
dns.resolver.NoNameservers,
|
||||||
|
dns.resolver.NoAnswer,
|
||||||
|
dns.exception.Timeout) as e:
|
||||||
|
return ("nok", (e.__class__.__name__, e))
|
||||||
|
|
||||||
|
if not full_answers:
|
||||||
|
answers = [answer.to_text() for answer in answers]
|
||||||
|
|
||||||
|
return ("ok", answers)
|
||||||
|
|
||||||
|
|
||||||
def _extract_inet(string, skip_netmask=False, skip_loopback=True):
|
def _extract_inet(string, skip_netmask=False, skip_loopback=True):
|
||||||
"""
|
"""
|
||||||
Extract IP addresses (v4 and/or v6) from a string limited to one
|
Extract IP addresses (v4 and/or v6) from a string limited to one
|
||||||
|
|
|
@ -37,10 +37,18 @@ def yunopaste(data):
|
||||||
|
|
||||||
def anonymize(data):
|
def anonymize(data):
|
||||||
|
|
||||||
|
def anonymize_domain(data, domain, redact):
|
||||||
|
data = data.replace(domain, redact)
|
||||||
|
# This stuff appears sometimes because some folder in
|
||||||
|
# /var/lib/metronome/ have some folders named this way
|
||||||
|
data = data.replace(domain.replace(".", "%2e"), redact.replace(".", "%2e"))
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
# First, let's replace every occurence of the main domain by "domain.tld"
|
# First, let's replace every occurence of the main domain by "domain.tld"
|
||||||
# This should cover a good fraction of the info leaked
|
# This should cover a good fraction of the info leaked
|
||||||
main_domain = _get_maindomain()
|
main_domain = _get_maindomain()
|
||||||
data = data.replace(main_domain, "maindomain.tld")
|
data = anonymize_domain(data, main_domain, "maindomain.tld")
|
||||||
|
|
||||||
# Next, let's replace other domains. We do this in increasing lengths,
|
# Next, let's replace other domains. We do this in increasing lengths,
|
||||||
# because e.g. knowing that the domain is a sub-domain of another domain may
|
# because e.g. knowing that the domain is a sub-domain of another domain may
|
||||||
|
@ -55,7 +63,7 @@ def anonymize(data):
|
||||||
for domain in domains:
|
for domain in domains:
|
||||||
if domain not in data:
|
if domain not in data:
|
||||||
continue
|
continue
|
||||||
data = data.replace(domain, "domain%s.tld" % count)
|
data = anonymize_domain(data, domain, "domain%s.tld" % count)
|
||||||
count += 1
|
count += 1
|
||||||
|
|
||||||
# We also want to anonymize the ips
|
# We also want to anonymize the ips
|
||||||
|
|
|
@ -49,6 +49,9 @@ def find_expected_string_keys():
|
||||||
for python_file in glob.glob("data/hooks/diagnosis/*.py"):
|
for python_file in glob.glob("data/hooks/diagnosis/*.py"):
|
||||||
content = open(python_file).read()
|
content = open(python_file).read()
|
||||||
for m in p3.findall(content):
|
for m in p3.findall(content):
|
||||||
|
if m.endswith("_"):
|
||||||
|
# Ignore some name fragments which are actually concatenated with other stuff..
|
||||||
|
continue
|
||||||
yield m
|
yield m
|
||||||
yield "diagnosis_description_" + os.path.basename(python_file)[:-3].split("-")[-1]
|
yield "diagnosis_description_" + os.path.basename(python_file)[:-3].split("-")[-1]
|
||||||
|
|
||||||
|
@ -123,6 +126,13 @@ def find_expected_string_keys():
|
||||||
for i in [1, 2, 3, 4]:
|
for i in [1, 2, 3, 4]:
|
||||||
yield "password_too_simple_%s" % i
|
yield "password_too_simple_%s" % i
|
||||||
|
|
||||||
|
checks = ["outgoing_port_25_ok", "ehlo_ok", "fcrdns_ok",
|
||||||
|
"blacklist_ok", "queue_ok", "ehlo_bad_answer",
|
||||||
|
"ehlo_unreachable", "ehlo_bad_answer_details",
|
||||||
|
"ehlo_unreachable_details", ]
|
||||||
|
for check in checks:
|
||||||
|
yield "diagnosis_mail_%s" % check
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Load en locale json keys #
|
# Load en locale json keys #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
Loading…
Add table
Reference in a new issue