Merge branch 'unstable' into feature224-envvarforscripts

This commit is contained in:
Jérôme Lebleu 2016-04-25 17:41:45 +02:00
commit b3cfbc21ac
72 changed files with 2561 additions and 2066 deletions

View file

@ -5,10 +5,6 @@ import os
import sys import sys
import argparse import argparse
import moulinette
from moulinette.actionsmap import ActionsMap
from moulinette.interfaces.cli import colorize, get_locale
# Either we are in a development environment or not # Either we are in a development environment or not
IN_DEVEL = False IN_DEVEL = False
@ -35,6 +31,11 @@ if IN_DEVEL:
LOG_DIR = os.path.join(basedir, 'log') LOG_DIR = os.path.join(basedir, 'log')
import moulinette
from moulinette.actionsmap import ActionsMap
from moulinette.interfaces.cli import colorize, get_locale
# Initialization & helpers functions ----------------------------------- # Initialization & helpers functions -----------------------------------
def _die(message, title='Error:'): def _die(message, title='Error:'):
@ -50,7 +51,7 @@ def _parse_cli_args():
help="Don't use actions map cache", help="Don't use actions map cache",
) )
parser.add_argument('--output-as', parser.add_argument('--output-as',
choices=['json', 'plain'], default=None, choices=['json', 'plain', 'none'], default=None,
help="Output result in another format", help="Output result in another format",
) )
parser.add_argument('--debug', parser.add_argument('--debug',
@ -149,6 +150,11 @@ def _init_moulinette(debug=False, verbose=False, quiet=False):
'handlers': [], 'handlers': [],
'propagate': True, 'propagate': True,
}, },
'moulinette.interface': {
'level': level,
'handlers': handlers,
'propagate': False,
},
}, },
'root': { 'root': {
'level': level, 'level': level,

View file

@ -5,10 +5,6 @@ import os
import sys import sys
import argparse import argparse
import moulinette
from moulinette.actionsmap import ActionsMap
from moulinette.interfaces.cli import colorize
# Either we are in a development environment or not # Either we are in a development environment or not
IN_DEVEL = False IN_DEVEL = False
@ -39,6 +35,11 @@ if IN_DEVEL:
LOG_DIR = os.path.join(basedir, 'log') LOG_DIR = os.path.join(basedir, 'log')
import moulinette
from moulinette.actionsmap import ActionsMap
from moulinette.interfaces.cli import colorize
# Initialization & helpers functions ----------------------------------- # Initialization & helpers functions -----------------------------------
def _die(message, title='Error:'): def _die(message, title='Error:'):

77
bin/yunopaste Executable file
View file

@ -0,0 +1,77 @@
#!/bin/bash
set -e
set -u
PASTE_URL="https://paste.yunohost.org"
_die() {
printf "Error: %s\n" "$*"
exit 1
}
check_dependencies() {
curl -V > /dev/null 2>&1 || _die "This script requires curl."
}
paste_data() {
json=$(curl -X POST -s -d "$1" "${PASTE_URL}/documents")
[[ -z "$json" ]] && _die "Unable to post the data to the server."
key=$(echo "$json" \
| python -c 'import json,sys;o=json.load(sys.stdin);print o["key"]' \
2>/dev/null)
[[ -z "$key" ]] && _die "Unable to parse the server response."
echo "${PASTE_URL}/${key}"
}
usage() {
printf "Usage: ${0} [OPTION]...
Read from input stream and paste the data to the YunoHost
Haste server.
For example, to paste the output of the YunoHost diagnosis, you
can simply execute the following:
yunohost tools diagnosis | ${0}
It will return the URL where you can access the pasted data.
Options:
-h, --help show this help message and exit
"
}
main() {
# parse options
while (( ${#} )); do
case "${1}" in
--help|-h)
usage
exit 0
;;
*)
echo "Unknown parameter detected: ${1}" >&2
echo >&2
usage >&2
exit 1
;;
esac
shift 1
done
# check input stream
read -t 0 || {
echo -e "Invalid usage: No input is provided.\n" >&2
usage
exit 1
}
paste_data "$(cat)"
}
check_dependencies
main "${@}"

View file

@ -516,6 +516,7 @@ app:
initdb: initdb:
action_help: Create database and initialize it with optionnal attached script action_help: Create database and initialize it with optionnal attached script
api: POST /tools/initdb api: POST /tools/initdb
deprecated: true
arguments: arguments:
user: user:
help: Name of the DB user help: Name of the DB user
@ -956,60 +957,36 @@ service:
default: 50 default: 50
type: int type: int
### service_regenconf() ### service_regen_conf()
regenconf: regen-conf:
action_help: > action_help: Regenerate the configuration file(s) for a service
Regenerate the configuration file(s) for a service and compare the result
with the existing configuration file.
Prints the differences between files if any.
api: PUT /services/regenconf api: PUT /services/regenconf
configuration: configuration:
lock: false lock: false
deprecated_alias:
- regenconf
arguments: arguments:
-s: names:
full: --service help: Services name to regenerate configuration of
help: Regenerate configuration for a specfic service nargs: "*"
-f: metavar: NAME
full: --force -d:
help: Override the current configuration with the newly generated one, even if it has been modified full: --with-diff
help: Show differences in case of configuration changes
action: store_true action: store_true
### service_safecopy()
safecopy:
action_help: >
Check if the specific file has been modified and display differences.
Stores the file hash in the services.yml file
arguments:
new_conf_file:
help: Path to the desired conf file
conf_file:
help: Path to the targeted conf file
-s:
full: --service
help: Service name attached to the conf file
extra:
required: True
-f: -f:
full: --force full: --force
help: Override the current configuration with the newly generated one, even if it has been modified help: >
Override all manual modifications in configuration
files
action: store_true action: store_true
-n:
### service_saferemove() full: --dry-run
saferemove: help: Show what would have been regenerated
action_help: > action: store_true
Check if the specific file has been modified before removing it. -p:
Backup the file in /home/yunohost.backup full: --list-pending
arguments: help: List pending configuration files and exit
conf_file:
help: Path to the targeted conf file
-s:
full: --service
help: Service name attached to the conf file
extra:
required: True
-f:
full: --force
help: Force file deletion
action: store_true action: store_true
############################# #############################
@ -1378,8 +1355,15 @@ hook:
nargs: "*" nargs: "*"
-a: -a:
full: --args full: --args
help: Ordered list of arguments to pass to the script help: Ordered list of arguments to pass to the scripts
nargs: "*" nargs: "*"
-q:
full: --no-trace
help: Do not print each command that will be executed
action: store_true
-d:
full: --chdir
help: The directory from where the scripts will be executed
### hook_exec() ### hook_exec()
exec: exec:
@ -1389,7 +1373,8 @@ hook:
help: Path of the script to execute help: Path of the script to execute
-a: -a:
full: --args full: --args
help: Arguments to pass to the script help: Ordered list of arguments to pass to the script
nargs: "*"
--raise-on-error: --raise-on-error:
help: Raise if the script returns a non-zero exit code help: Raise if the script returns a non-zero exit code
action: store_true action: store_true

View file

@ -48,27 +48,33 @@ ynh_package_install() {
# usage: ynh_package_install_from_equivs controlfile # usage: ynh_package_install_from_equivs controlfile
# | arg: controlfile - path of the equivs control file # | arg: controlfile - path of the equivs control file
ynh_package_install_from_equivs() { ynh_package_install_from_equivs() {
controlfile=$1
# install equivs package as needed
ynh_package_is_installed 'equivs' \ ynh_package_is_installed 'equivs' \
|| ynh_package_install equivs || ynh_package_install equivs
# retrieve package information # retrieve package information
pkgname=$(grep '^Package: ' $1 | cut -d' ' -f 2) pkgname=$(grep '^Package: ' $controlfile | cut -d' ' -f 2)
pkgversion=$(grep '^Version: ' $1 | cut -d' ' -f 2) pkgversion=$(grep '^Version: ' $controlfile | cut -d' ' -f 2)
[[ -z "$pkgname" || -z "$pkgversion" ]] \ [[ -z "$pkgname" || -z "$pkgversion" ]] \
&& echo "Invalid control file" && exit 1 && echo "Invalid control file" && exit 1
controlfile=$(readlink -f "$1")
# update packages cache # update packages cache
ynh_package_update ynh_package_update
# build and install the package # build and install the package
TMPDIR=$(ynh_mkdir_tmp) TMPDIR=$(ynh_mkdir_tmp)
(cd $TMPDIR \ (cp "$controlfile" "${TMPDIR}/control" \
&& equivs-build "$controlfile" 1>/dev/null \ && cd "$TMPDIR" \
&& equivs-build ./control 1>/dev/null \
&& sudo dpkg --force-depends \ && sudo dpkg --force-depends \
-i "./${pkgname}_${pkgversion}_all.deb" 2>&1 \ -i "./${pkgname}_${pkgversion}_all.deb" 2>&1 \
&& sudo apt-get -f -y -qq install) \ && sudo apt-get -f -y -qq install) \
&& ([[ -n "$TMPDIR" ]] && rm -rf $TMPDIR) && ([[ -n "$TMPDIR" ]] && rm -rf $TMPDIR)
# check if the package is actually installed
ynh_package_is_installed "$pkgname"
} }
# Remove package(s) # Remove package(s)

View file

@ -20,6 +20,17 @@ ynh_user_get_info() {
sudo yunohost user info "$1" --output-as plain | ynh_get_plain_key "$2" sudo yunohost user info "$1" --output-as plain | ynh_get_plain_key "$2"
} }
# Get the list of YunoHost users
#
# example: for u in $(ynh_user_list); do ...
#
# usage: ynh_user_list
# | ret: string - one username per line
ynh_user_list() {
sudo yunohost user list --output-as plain --quiet \
| awk '/^##username$/{getline; print}'
}
# Check if a user exists on the system # Check if a user exists on the system
# #
# usage: ynh_system_user_exists username # usage: ynh_system_user_exists username

View file

@ -1,4 +1,4 @@
backup_dir="$1/conf/ynh/mysql" backup_dir="$1/conf/ynh/mysql"
sudo mkdir -p $backup_dir sudo mkdir -p $backup_dir
sudo cp -a /etc/yunohost/mysql $backup_dir/ sudo cp -a /etc/yunohost/mysql "${backup_dir}/root_pwd"

View file

@ -1,7 +1,4 @@
backup_dir="$1/conf/ynh/" backup_dir="$1/conf/ynh"
backup_dir_legacy="$1/yunohost/"
sudo mkdir -p $backup_dir sudo mkdir -p $backup_dir
sudo mkdir -p $backup_dir_legacy
sudo cp -a /etc/yunohost/current_host $backup_dir sudo cp -a /etc/yunohost/current_host "${backup_dir}/current_host"
sudo cp -a /etc/yunohost/current_host $backup_dir_legacy

122
data/hooks/conf_regen/01-yunohost Normal file → Executable file
View file

@ -1,25 +1,111 @@
set -e #!/bin/bash
force=$1 set -e
cd /usr/share/yunohost/templates/yunohost services_path="/etc/yunohost/services.yml"
sudo mkdir -p /etc/yunohost do_init_regen() {
if [[ $EUID -ne 0 ]]; then
echo "You must be root to run this script" 1>&2
exit 1
fi
if [ ! -f /etc/yunohost/current_host ]; then cd /usr/share/yunohost/templates/yunohost
echo "yunohost.org" | sudo tee /etc/yunohost/current_host
fi
if [ ! -f /etc/yunohost/firewall.yml ]; then [[ -d /etc/yunohost ]] || mkdir -p /etc/yunohost
sudo cp firewall.yml /etc/yunohost/firewall.yml
fi
if [ ! -f /etc/yunohost/services.yml ]; then # set default current_host
sudo cp services.yml /etc/yunohost/services.yml [[ -f /etc/yunohost/current_host ]] \
fi || echo "yunohost.org" > /etc/yunohost/current_host
# Allow users to access /media directory # copy default services and firewall
if [ ! -d /etc/skel/media ]; then [[ -f $services_path ]] \
mkdir -p /media || cp services.yml "$services_path"
ln -s /media /etc/skel/ [[ -f /etc/yunohost/firewall.yml ]] \
fi || cp firewall.yml /etc/yunohost/firewall.yml
# allow users to access /media directory
[[ -d /etc/skel/media ]] \
|| (mkdir -p /media && ln -s /media /etc/skel/media)
}
do_pre_regen() {
pending_dir=$1
cd /usr/share/yunohost/templates/yunohost
# update services.yml
if [[ -f $services_path ]]; then
tmp_services_path="${services_path}-tmp"
new_services_path="${services_path}-new"
sudo cp "$services_path" "$tmp_services_path"
_update_services "$new_services_path" || {
sudo mv "$tmp_services_path" "$services_path"
exit 1
}
if [[ -f $new_services_path ]]; then
# replace services.yml with new one
sudo mv "$new_services_path" "$services_path"
sudo mv "$tmp_services_path" "${services_path}-old"
else
sudo rm -f "$tmp_services_path"
fi
else
sudo cp services.yml /etc/yunohost/services.yml
fi
}
_update_services() {
sudo python2 - << EOF
import yaml
with open('services.yml') as f:
new_services = yaml.load(f)
with open('/etc/yunohost/services.yml') as f:
services = yaml.load(f)
updated = False
for service, conf in new_services.items():
# remove service with empty conf
if not conf:
if service in services:
print("removing '{0}' from services".format(service))
del services[service]
updated = True
# add new service
elif not services.get(service, None):
print("adding '{0}' to services".format(service))
services[service] = conf
updated = True
# update service conf
else:
conffiles = services[service].pop('conffiles', {})
if services[service] != conf:
print("update '{0}' service".format(service))
services[service].update(conf)
updated = True
if conffiles:
services[service]['conffiles'] = conffiles
if updated:
with open('/etc/yunohost/services.yml-new', 'w') as f:
yaml.safe_dump(services, f, default_flow_style=False)
EOF
}
FORCE=${2:-0}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

135
data/hooks/conf_regen/02-ssl Normal file → Executable file
View file

@ -1,64 +1,93 @@
set -e #!/bin/bash
force=$1 set -e
function safe_copy () { ssl_dir="/usr/share/yunohost/yunohost-config/ssl/yunoCA"
if [ ! -f /etc/yunohost/installed ]; then
sudo cp $1 $2 do_init_regen() {
else if [[ $EUID -ne 0 ]]; then
if [ $force ]; then echo "You must be root to run this script" 1>&2
sudo yunohost service safecopy \ exit 1
-s ssl $1 $2 --force fi
else
sudo yunohost service safecopy \ # create certs and SSL directories
-s ssl $1 $2 mkdir -p "/etc/yunohost/certs/yunohost.org"
fi mkdir -p "${ssl_dir}/"{ca,certs,crl,newcerts}
fi
# initialize some files
[[ -f "${ssl_dir}/serial" ]] \
|| echo "00" > "${ssl_dir}/serial"
[[ -f "${ssl_dir}/index.txt" ]] \
|| touch "${ssl_dir}/index.txt"
openssl_conf="/usr/share/yunohost/templates/ssl/openssl.cnf"
# create default certificates
if [[ ! -f /etc/yunohost/certs/yunohost.org/ca.pem ]]; then
openssl req -x509 -new -config "$openssl_conf" \
-days 3650 -out "${ssl_dir}/ca/cacert.pem" \
-keyout "${ssl_dir}/ca/cakey.pem" -nodes -batch 2>&1
cp "${ssl_dir}/ca/cacert.pem" \
/etc/yunohost/certs/yunohost.org/ca.pem
ln -sf /etc/yunohost/certs/yunohost.org/ca.pem \
/etc/ssl/certs/ca-yunohost_crt.pem
update-ca-certificates
fi
if [[ ! -f /etc/yunohost/certs/yunohost.org/crt.pem ]]; then
openssl req -new -config "$openssl_conf" \
-days 730 -out "${ssl_dir}/certs/yunohost_csr.pem" \
-keyout "${ssl_dir}/certs/yunohost_key.pem" -nodes -batch 2>&1
openssl ca -config "$openssl_conf" \
-days 730 -in "${ssl_dir}/certs/yunohost_csr.pem" \
-out "${ssl_dir}/certs/yunohost_crt.pem" -batch 2>&1
last_cert=$(ls $ssl_dir/newcerts/*.pem | sort -V | tail -n 1)
chmod 640 "${ssl_dir}/certs/yunohost_key.pem"
chmod 640 "$last_cert"
cp "${ssl_dir}/certs/yunohost_key.pem" \
/etc/yunohost/certs/yunohost.org/key.pem
cp "$last_cert" \
/etc/yunohost/certs/yunohost.org/crt.pem
ln -sf /etc/yunohost/certs/yunohost.org/crt.pem \
/etc/ssl/certs/yunohost_crt.pem
ln -sf /etc/yunohost/certs/yunohost.org/key.pem \
/etc/ssl/private/yunohost_key.pem
fi
} }
cd /usr/share/yunohost/templates/ssl do_pre_regen() {
ssl_dir=/usr/share/yunohost/yunohost-config/ssl/yunoCA pending_dir=$1
sudo mkdir -p /etc/yunohost/certs/yunohost.org cd /usr/share/yunohost/templates/ssl
sudo mkdir -p $ssl_dir/{ca,certs,crl,newcerts}
safe_copy openssl.cnf $ssl_dir/openssl.cnf install -D -m 644 openssl.cnf "${pending_dir}/${ssl_dir}/openssl.cnf"
}
[ -f $ssl_dir/serial ] \ do_post_regen() {
|| (echo "00" | sudo tee $ssl_dir/serial) regen_conf_files=$1
[ -f $ssl_dir/index.txt ] \ # TODO: regenerate certificates if conf changed?
|| sudo touch $ssl_dir/index.txt }
if [ ! -f /etc/yunohost/certs/yunohost.org/ca.pem ]; then FORCE=${2:-0}
sudo openssl req -x509 -new -config $ssl_dir/openssl.cnf \ DRY_RUN=${3:-0}
-days 3650 -out $ssl_dir/ca/cacert.pem \
-keyout $ssl_dir/ca/cakey.pem -nodes -batch
sudo cp $ssl_dir/ca/cacert.pem \
/etc/yunohost/certs/yunohost.org/ca.pem
sudo ln -sf /etc/yunohost/certs/yunohost.org/ca.pem \
/etc/ssl/certs/ca-yunohost_crt.pem
sudo update-ca-certificates
fi
if [ ! -f /etc/yunohost/certs/yunohost.org/crt.pem ]; then case "$1" in
sudo openssl req -new -config $ssl_dir/openssl.cnf \ pre)
-days 730 -out $ssl_dir/certs/yunohost_csr.pem \ do_pre_regen $4
-keyout $ssl_dir/certs/yunohost_key.pem -nodes -batch ;;
sudo openssl ca -config $ssl_dir/openssl.cnf \ post)
-days 730 -in $ssl_dir/certs/yunohost_csr.pem \ do_post_regen $4
-out $ssl_dir/certs/yunohost_crt.pem -batch ;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
last_cert=$(ls $ssl_dir/newcerts/*.pem | sort -V | tail -n 1) exit 0
sudo chmod 640 $ssl_dir/certs/yunohost_key.pem
sudo chmod 640 $last_cert
sudo cp $ssl_dir/certs/yunohost_key.pem \
/etc/yunohost/certs/yunohost.org/key.pem
sudo cp $last_cert \
/etc/yunohost/certs/yunohost.org/crt.pem
sudo ln -sf /etc/yunohost/certs/yunohost.org/crt.pem \
/etc/ssl/certs/yunohost_crt.pem
sudo ln -sf /etc/yunohost/certs/yunohost.org/key.pem \
/etc/ssl/private/yunohost_key.pem
fi

63
data/hooks/conf_regen/03-ssh Normal file → Executable file
View file

@ -1,30 +1,45 @@
set -e #!/bin/bash
force=$1 set -e
function safe_copy () { do_pre_regen() {
if [ $force ]; then pending_dir=$1
sudo yunohost service safecopy \
-s ssh \ cd /usr/share/yunohost/templates/ssh
$1 $2 \
--force # only overwrite SSH configuration on an ISO installation
else if [[ ! -f /etc/yunohost/from_script ]]; then
sudo yunohost service safecopy \ # do not listen to IPv6 if unavailable
-s ssh \ [[ -f /proc/net/if_inet6 ]] \
$1 $2 || sed -i "s/ListenAddress ::/#ListenAddress ::/g" sshd_config
fi
install -D -m 644 sshd_config "${pending_dir}/etc/ssh/sshd_config"
fi
} }
cd /usr/share/yunohost/templates/ssh do_post_regen() {
regen_conf_files=$1
# Only overwrite SSH configuration on an ISO installation if [[ ! -f /etc/yunohost/from_script ]]; then
if [ ! -f /etc/yunohost/from_script ]; then [[ -z "$regen_conf_files" ]] \
|| sudo service ssh restart
fi
}
# Do not listen to IPv6 if unavailable FORCE=${2:-0}
if [ ! -f /proc/net/if_inet6 ]; then DRY_RUN=${3:-0}
sudo sed -i "s/ListenAddress ::/#ListenAddress ::/g" sshd_config
fi case "$1" in
safe_copy sshd_config /etc/ssh/sshd_config pre)
do_pre_regen $4
sudo service ssh restart ;;
fi post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

165
data/hooks/conf_regen/06-slapd Normal file → Executable file
View file

@ -1,71 +1,118 @@
set -e #!/bin/bash
force=$1 set -e
function safe_copy () { do_init_regen() {
if [ ! -f /etc/yunohost/installed ]; then if [[ $EUID -ne 0 ]]; then
sudo cp $1 $2 echo "You must be root to run this script" 1>&2
else exit 1
if [[ "$force" == "True" ]]; then fi
sudo yunohost service safecopy \
-s slapd $1 $2 --force do_pre_regen ""
else
sudo yunohost service safecopy \ # fix some permissions
-s slapd $1 $2 chown root:openldap /etc/ldap/slapd.conf
fi chown -R openldap:openldap /etc/ldap/schema/
fi
# check the slapd config file at first
slaptest -Q -u -f /etc/ldap/slapd.conf
# regenerate LDAP config directory from slapd.conf
rm -Rf /etc/ldap/slapd.d
mkdir /etc/ldap/slapd.d
slaptest -f /etc/ldap/slapd.conf -F /etc/ldap/slapd.d/ 2>&1
chown -R openldap:openldap /etc/ldap/slapd.d/
service slapd restart
} }
cd /usr/share/yunohost/templates/slapd do_pre_regen() {
pending_dir=$1
# Remove legacy configuration file cd /usr/share/yunohost/templates/slapd
[ ! -f /etc/yunohost/installed ] \
|| sudo yunohost service saferemove -s slapd \
/etc/ldap/slapd-yuno.conf
# Retrieve current backend # remove legacy configuration file
backend=$(sudo slapcat -n 0 | sed -n 's/^dn: olcDatabase={1}\(.*\),cn=config$/\1/p') [ ! -f /etc/ldap/slapd-yuno.conf ] \
|| touch "${pending_dir}/etc/ldap/slapd-yuno.conf"
# Save current database in case of a backend change # create needed directories
BACKEND_CHANGE=0 ldap_dir="${pending_dir}/etc/ldap"
BACKUP_DIR="/var/backups/dc=yunohost,dc=org-${backend}-$(date +%s)" schema_dir="${ldap_dir}/schema"
if [[ -n "$backend" && "$backend" != "mdb" && "$force" == "True" ]]; then mkdir -p "$ldap_dir" "$schema_dir"
BACKEND_CHANGE=1
sudo mkdir -p "$BACKUP_DIR"
sudo slapcat -b dc=yunohost,dc=org \
-l "${BACKUP_DIR}/dc=yunohost-dc=org.ldif"
fi
safe_copy sudo.schema /etc/ldap/schema/sudo.schema # copy configuration files
safe_copy mailserver.schema /etc/ldap/schema/mailserver.schema cp -a ldap.conf slapd.conf "$ldap_dir"
safe_copy ldap.conf /etc/ldap/ldap.conf cp -a sudo.schema mailserver.schema "$schema_dir"
safe_copy slapd.default /etc/default/slapd
safe_copy slapd.conf /etc/ldap/slapd.conf
# Fix some permissions install -D -m 644 slapd.default "${pending_dir}/etc/default/slapd"
sudo chown root:openldap /etc/ldap/slapd.conf }
sudo chown -R openldap:openldap /etc/ldap/schema/
sudo chown -R openldap:openldap /etc/ldap/slapd.d/
# Check the slapd config file at first do_post_regen() {
sudo slaptest -Q -u -f /etc/ldap/slapd.conf regen_conf_files=$1
if [[ $BACKEND_CHANGE -eq 1 ]]; then # fix some permissions
# Regenerate LDAP config directory and import database as root sudo chown root:openldap /etc/ldap/slapd.conf
# since the admin user may be unavailable sudo chown -R openldap:openldap /etc/ldap/schema/
sudo sh -c "rm -Rf /etc/ldap/slapd.d; sudo chown -R openldap:openldap /etc/ldap/slapd.d/
mkdir /etc/ldap/slapd.d;
slaptest -f /etc/ldap/slapd.conf -F /etc/ldap/slapd.d;
chown -R openldap:openldap /etc/ldap/slapd.d;
slapadd -F /etc/ldap/slapd.d -b dc=yunohost,dc=org \
-l '${BACKUP_DIR}/dc=yunohost-dc=org.ldif';
chown -R openldap:openldap /var/lib/ldap" 2>&1
else
# Regenerate LDAP config directory from slapd.conf
sudo rm -Rf /etc/ldap/slapd.d
sudo mkdir /etc/ldap/slapd.d
sudo slaptest -f /etc/ldap/slapd.conf -F /etc/ldap/slapd.d/ 2>&1
sudo chown -R openldap:openldap /etc/ldap/slapd.d/
fi
sudo service slapd force-reload [ -z "$regen_conf_files" ] && exit 0
# retrieve current and new backends
curr_backend=$(sudo slapcat -n 0 \
| sed -n 's/^dn: olcDatabase={1}\(.*\),cn=config$/\1/p')
new_backend=$(grep '^database' /etc/ldap/slapd.conf | awk '{print $2}')
# save current database in case of a backend change
backend_change=0
backup_dir="/var/backups/dc=yunohost,dc=org-${curr_backend}-$(date +%s)"
if [[ -n "$curr_backend" && "$curr_backend" != "$new_backend" ]]; then
backend_change=1
sudo mkdir -p "$backup_dir"
sudo slapcat -b dc=yunohost,dc=org \
-l "${backup_dir}/dc=yunohost-dc=org.ldif"
fi
# check the slapd config file at first
sudo slaptest -Q -u -f /etc/ldap/slapd.conf
if [[ $backend_change -eq 1 ]]; then
# regenerate LDAP config directory and import database as root
# since the admin user may be unavailable
sudo sh -c "rm -Rf /etc/ldap/slapd.d;
mkdir /etc/ldap/slapd.d;
slaptest -f /etc/ldap/slapd.conf -F /etc/ldap/slapd.d;
chown -R openldap:openldap /etc/ldap/slapd.d;
slapadd -F /etc/ldap/slapd.d -b dc=yunohost,dc=org \
-l '${backup_dir}/dc=yunohost-dc=org.ldif';
chown -R openldap:openldap /var/lib/ldap" 2>&1
else
# regenerate LDAP config directory from slapd.conf
sudo rm -Rf /etc/ldap/slapd.d
sudo mkdir /etc/ldap/slapd.d
sudo slaptest -f /etc/ldap/slapd.conf -F /etc/ldap/slapd.d/ 2>&1
sudo chown -R openldap:openldap /etc/ldap/slapd.d/
fi
sudo service slapd force-reload
}
FORCE=${2:-0}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

48
data/hooks/conf_regen/09-nslcd Normal file → Executable file
View file

@ -1,26 +1,36 @@
set -e #!/bin/bash
force=$1 set -e
function safe_copy () { do_pre_regen() {
if [[ "$force" == "True" ]]; then pending_dir=$1
sudo yunohost service safecopy \
-s nslcd \ cd /usr/share/yunohost/templates/nslcd
$1 $2 \
--force install -D -m 644 nslcd.conf "${pending_dir}/etc/nslcd.conf"
else
sudo yunohost service safecopy \
-s nslcd \
$1 $2
fi
} }
cd /usr/share/yunohost/templates/nslcd do_post_regen() {
regen_conf_files=$1
safe_copy nslcd.conf /etc/nslcd.conf [[ -z "$regen_conf_files" ]] \
|| sudo service nslcd restart
}
# Fix: Add a blank line at the end of the file FORCE=${2:-0}
# to avoid nscld restart failure DRY_RUN=${3:-0}
echo -e "\n" | sudo tee -a /etc/nslcd.conf
sudo service nslcd restart case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

120
data/hooks/conf_regen/12-metronome Normal file → Executable file
View file

@ -1,66 +1,76 @@
set -e #!/bin/bash
force=$1 set -e
function safe_copy () { do_pre_regen() {
if [[ "$force" == "True" ]]; then pending_dir=$1
sudo yunohost service safecopy \
-s metronome \ cd /usr/share/yunohost/templates/metronome
$1 $2 \
--force # create directories for pending conf
else metronome_dir="${pending_dir}/etc/metronome"
sudo yunohost service safecopy \ metronome_conf_dir="${metronome_dir}/conf.d"
-s metronome \ mkdir -p "$metronome_conf_dir"
$1 $2
fi # retrieve variables
main_domain=$(cat /etc/yunohost/current_host)
domain_list=$(sudo yunohost domain list --output-as plain --quiet)
# install main conf file
cat metronome.cfg.lua \
| sed "s/{{ main_domain }}/${main_domain}/g" \
> "${metronome_dir}/metronome.cfg.lua"
# add domain conf files
for domain in $domain_list; do
cat domain.tpl.cfg.lua \
| sed "s/{{ domain }}/${domain}/g" \
> "${metronome_conf_dir}/${domain}.cfg.lua"
done
# remove old domain conf files
conf_files=$(ls -1 /etc/metronome/conf.d \
| awk '/^[^\.]+\.[^\.]+.*\.cfg\.lua$/ { print $1 }')
for file in $conf_files; do
domain=${file%.cfg.lua}
[[ $domain_list =~ $domain ]] \
|| touch "${metronome_conf_dir}/${file}"
done
} }
cd /usr/share/yunohost/templates/metronome do_post_regen() {
regen_conf_files=$1
# Copy configuration files # fix some permissions
main_domain=$(cat /etc/yunohost/current_host) sudo chown -R metronome: /var/lib/metronome/
cat metronome.cfg.lua.sed \ sudo chown -R metronome: /etc/metronome/conf.d/
| sed "s/{{ main_domain }}/$main_domain/g" \
| sudo tee metronome.cfg.lua
safe_copy metronome.cfg.lua /etc/metronome/metronome.cfg.lua
need_restart=False # retrieve variables
sudo mkdir -p /etc/metronome/conf.d domain_list=$(sudo yunohost domain list --output-as plain --quiet)
domain_list=$(sudo yunohost domain list --output-as plain) # create metronome directories for domains
for domain in $domain_list; do
sudo mkdir -p "/var/lib/metronome/${domain//./%2e}/pep"
done
# Copy a configuration file for each YunoHost domain [[ -z "$regen_conf_files" ]] \
for domain in $domain_list; do || sudo service metronome restart
sanitzed_domain="$(echo $domain | sed 's/\./%2e/g')" }
sudo mkdir -p /var/lib/metronome/$sanitzed_domain/pep
cat domain.cfg.lua.sed \ FORCE=${2:-0}
| sed "s/{{ domain }}/$domain/g" \ DRY_RUN=${3:-0}
| sudo tee $domain.cfg.lua
if [[ $(safe_copy $domain.cfg.lua /etc/metronome/conf.d/$domain.cfg.lua | tail -n1) == "True" ]]; then
need_restart=True
fi
done
# Remove old domains files case "$1" in
for file in /etc/metronome/conf.d/*; do pre)
domain=$(echo $file \ do_pre_regen $4
| sed 's|/etc/metronome/conf.d/||' \ ;;
| sed 's|.cfg.lua||') post)
sanitzed_domain="$(echo $domain | sed 's/\./%2e/g')" do_post_regen $4
[[ $domain_list =~ $domain ]] \ ;;
|| ([[ $(sudo yunohost service saferemove -s metronome $file | tail -n1) == "True" ]] \ *)
&& sudo rm -rf /var/lib/metronome/$sanitzed_domain) echo "hook called with unknown argument \`$1'" >&2
done exit 1
;;
esac
# Create domain directory exit 0
sudo chown -R metronome: /var/lib/metronome/
sudo chown -R metronome: /etc/metronome/conf.d/
# Restart if need be
if [[ "$need_restart" == "True" ]]; then
sudo service metronome restart
else
sudo service metronome reload \
|| sudo service metronome restart
fi

153
data/hooks/conf_regen/15-nginx Normal file → Executable file
View file

@ -1,86 +1,101 @@
set -e #!/bin/bash
force=$1 set -e
function safe_copy () { do_init_regen() {
if [ ! -f /etc/yunohost/installed ]; then if [[ $EUID -ne 0 ]]; then
sudo cp $1 $2 echo "You must be root to run this script" 1>&2
else exit 1
if [[ "$force" == "True" ]]; then fi
sudo yunohost service safecopy \
-s nginx \ do_pre_regen ""
$1 $2 \
--force
else
sudo yunohost service safecopy \
-s nginx \
$1 $2
fi
fi
} }
cd /usr/share/yunohost/templates/nginx do_pre_regen() {
pending_dir=$1
# Copy plain single configuration files cd /usr/share/yunohost/templates/nginx
files="ssowat.conf
global.conf
yunohost_admin.conf
yunohost_admin.conf.inc
yunohost_api.conf.inc
yunohost_panel.conf.inc"
for file in $files; do nginx_dir="${pending_dir}/etc/nginx"
safe_copy $file /etc/nginx/conf.d/$file nginx_conf_dir="${nginx_dir}/conf.d"
done mkdir -p "$nginx_conf_dir"
# install plain conf files
cp plain/* "$nginx_conf_dir"
if [ -f /etc/yunohost/installed ]; then # probably run with init: just disable default site, restart NGINX and exit
if [[ -z "$pending_dir" ]]; then
rm -f "${nginx_dir}/sites-enabled/default"
service nginx restart
exit 0
fi
need_restart=False # retrieve variables
domain_list=$(sudo yunohost domain list --output-as plain) main_domain=$(cat /etc/yunohost/current_host)
domain_list=$(sudo yunohost domain list --output-as plain --quiet)
# Copy a configuration file for each YunoHost domain # add domain conf files
for domain in $domain_list; do for domain in $domain_list; do
sudo mkdir -p /etc/nginx/conf.d/$domain.d domain_conf_dir="${nginx_conf_dir}/${domain}.d"
cat server.conf.sed \ mkdir -p "$domain_conf_dir"
| sed "s/{{ domain }}/$domain/g" \
| sudo tee $domain.conf
[[ $(safe_copy $domain.conf /etc/nginx/conf.d/$domain.conf | tail -n1) == "True" ]] \
&& need_restart=True
[ -f /etc/nginx/conf.d/$domain.d/yunohost_local.conf ] \ # NGINX server configuration
&& [[ $main_domain != $domain ]] \ cat server.tpl.conf \
&& sudo yunohost service saferemove -s nginx \ | sed "s/{{ domain }}/${domain}/g" \
/etc/nginx/conf.d/$domain.d/yunohost_local.conf > "${nginx_conf_dir}/${domain}.conf"
done
[[ $main_domain != $domain ]] \
&& touch "${domain_conf_dir}/yunohost_local.conf" \
|| cp yunohost_local.conf "${domain_conf_dir}/yunohost_local.conf"
done
# Copy 'yunohost.local' to the main domain conf directory # remove old domain conf files
main_domain=$(cat /etc/yunohost/current_host) conf_files=$(ls -1 /etc/nginx/conf.d \
safe_copy yunohost_local.conf \ | awk '/^[^\.]+\.[^\.]+.*\.conf$/ { print $1 }')
/etc/nginx/conf.d/$main_domain.d/yunohost_local.conf for file in $conf_files; do
domain=${file%.conf}
[[ $domain_list =~ $domain ]] \
|| touch "${nginx_conf_dir}/${file}"
done
# disable default site
mkdir -p "${nginx_dir}/sites-enabled"
touch "${nginx_dir}/sites-enabled/default"
}
# Remove old domains files do_post_regen() {
for file in /etc/nginx/conf.d/*.*.conf; do regen_conf_files=$1
domain=$(echo $file \
| sed 's|/etc/nginx/conf.d/||' \
| sed 's|.conf||')
[[ $domain_list =~ $domain ]] \
|| ([[ $(sudo yunohost service saferemove -s nginx $file) == "True" ]] \
&& (sudo rm -r /etc/nginx/conf.d/$domain.d || true))
done
else [ -z "$regen_conf_files" ] && exit 0
[ ! -f /etc/nginx/sites-available/default ] \
|| sudo rm -f /etc/nginx/sites-enabled/default
need_restart=True
fi
# Restart if need be # retrieve variables
if [[ "$need_restart" == "True" ]]; then domain_list=$(sudo yunohost domain list --output-as plain --quiet)
sudo service nginx restart
else # create NGINX conf directories for domains
sudo service nginx reload \ for domain in $domain_list; do
|| sudo service nginx restart sudo mkdir -p "/etc/nginx/conf.d/${domain}.d"
fi done
sudo service nginx restart
}
FORCE=${2:-0}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

96
data/hooks/conf_regen/19-postfix Normal file → Executable file
View file

@ -1,56 +1,56 @@
set -e #!/bin/bash
force=$1 set -e
function safe_copy () { do_pre_regen() {
if [[ "$force" == "True" ]]; then pending_dir=$1
sudo yunohost service safecopy \
-s postfix \ cd /usr/share/yunohost/templates/postfix
$1 $2 \
--force postfix_dir="${pending_dir}/etc/postfix"
else mkdir -p "$postfix_dir"
sudo yunohost service safecopy \
-s postfix \ # install plain conf files
$1 $2 cp plain/* "$postfix_dir"
fi
# prepare main.cf conf file
main_domain=$(cat /etc/yunohost/current_host)
cat main.cf \
| sed "s/{{ main_domain }}/${main_domain}/g" \
> "${postfix_dir}/main.cf"
# adapt it for IPv4-only hosts
if [ ! -f /proc/net/if_inet6 ]; then
sed -i \
's/ \[::ffff:127.0.0.0\]\/104 \[::1\]\/128//g' \
"${postfix_dir}/main.cf"
sed -i \
's/inet_interfaces = all/&\ninet_protocols = ipv4/' \
"${postfix_dir}/main.cf"
fi
} }
cd /usr/share/yunohost/templates/postfix do_post_regen() {
regen_conf_files=$1
# Copy plain single configuration files [[ -z "$regen_conf_files" ]] \
files="header_checks || sudo service postfix restart
ldap-accounts.cf }
ldap-aliases.cf
ldap-domains.cf
master.cf
sender_canonical
smtp_reply_filter"
for file in $files; do FORCE=${2:-0}
safe_copy $file /etc/postfix/$file DRY_RUN=${3:-0}
done
main_domain=$(cat /etc/yunohost/current_host) case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
# Replace main domain in the main configuration file exit 0
cat main.cf.sed \
| sed "s/{{ main_domain }}/$main_domain/g" \
| sudo tee main.cf
# And adapt it to IPv4-only hosts
if [ ! -f /proc/net/if_inet6 ]; then
sudo sed -i \
's/ \[::ffff:127.0.0.0\]\/104 \[::1\]\/128//g' \
main.cf
sudo sed -i \
's/inet_interfaces = all/inet_interfaces = all\ninet_protocols = ipv4/' \
main.cf
fi
if [[ $(safe_copy main.cf /etc/postfix/main.cf) == "True" ]]; then
sudo service postfix restart
else
sudo service postfix reload \
|| sudo service postfix restart
fi

View file

@ -1,43 +0,0 @@
set -e
# Execute this hook only if we force the configuration regeneration
if [[ "$1" == "True" ]]; then
# Add new email services
sudo yunohost service add rspamd -l /var/log/mail.log \
|| echo "rspamd is already listed in services"
sudo yunohost service add rmilter -l /var/log/mail.log \
|| echo "rmilter is already listed in services"
sudo yunohost service add redis-server -l /var/log/redis/redis-server.log \
|| echo "redis-server is already listed in services"
# Remove previous email services
systemctl is-enabled spamassassin > /dev/null 2>&1 \
&& sudo systemctl disable spamassassin
systemctl is-active spamassassin > /dev/null \
&& sudo systemctl stop spamassassin
sudo rm -f /etc/cron.daily/spamassassin
sudo yunohost service status spamassassin > /dev/null 2>&1 \
&& sudo yunohost service remove spamassassin
# 'systemctl is-enabled' does not work for service with no systemd unit file
sudo ls /etc/rc2.d/S??amavis > /dev/null 2>&1 \
|| sudo systemctl disable amavis
sudo systemctl is-active amavis > /dev/null \
&& sudo systemctl stop amavis
sudo yunohost service status amavis > /dev/null 2>&1 \
&& sudo yunohost service remove amavis
# 'systemctl is-enabled' does not work for service with no systemd unit file
sudo ls /etc/rc2.d/S??postgrey > /dev/null 2>&1 \
|| sudo systemctl disable postgrey
sudo systemctl is-active postgrey > /dev/null \
&& sudo systemctl stop postgrey
sudo yunohost service status postgrey > /dev/null 2>&1 \
&& sudo yunohost service remove postgrey
fi
exit 0

96
data/hooks/conf_regen/25-dovecot Normal file → Executable file
View file

@ -1,51 +1,69 @@
set -e #!/bin/bash
force=$1 set -e
function safe_copy () { do_pre_regen() {
if [[ "$force" == "True" ]]; then pending_dir=$1
sudo yunohost service safecopy \
-s dovecot $1 $2 --force cd /usr/share/yunohost/templates/dovecot
else
sudo yunohost service safecopy \ dovecot_dir="${pending_dir}/etc/dovecot"
-s dovecot $1 $2 mkdir -p "${dovecot_dir}/global_script"
fi
# copy simple conf files
cp dovecot-ldap.conf "${dovecot_dir}/dovecot-ldap.conf"
cp dovecot.sieve "${dovecot_dir}/global_script/dovecot.sieve"
# prepare dovecot.conf conf file
main_domain=$(cat /etc/yunohost/current_host)
cat dovecot.conf \
| sed "s/{{ main_domain }}/${main_domain}/g" \
> "${dovecot_dir}/dovecot.conf"
# adapt it for IPv4-only hosts
if [ ! -f /proc/net/if_inet6 ]; then
sed -i \
's/^\(listen =\).*/\1 */' \
"${dovecot_dir}/dovecot.conf"
fi
} }
cd /usr/share/yunohost/templates/dovecot do_post_regen() {
regen_conf_files=$1
# Create vmail user # create vmail user
sudo id vmail > /dev/null 2>&1 \ id vmail > /dev/null 2>&1 \
|| sudo adduser --system --ingroup mail --uid 500 vmail || sudo adduser --system --ingroup mail --uid 500 vmail
# fix permissions
sudo chown -R vmail:mail /etc/dovecot/global_script
sudo chmod 770 /etc/dovecot/global_script
# Replace main domain in the main configuration file [ -z "$regen_conf_files" ] && exit 0
main_domain=$(cat /etc/yunohost/current_host)
cat dovecot.conf.sed \
| sed "s/{{ main_domain }}/$main_domain/g" \
| sudo tee dovecot.conf
# compile sieve script
[[ "$regen_conf_files" =~ dovecot\.sieve ]] && {
sudo sievec /etc/dovecot/global_script/dovecot.sieve
sudo chown -R vmail:mail /etc/dovecot/global_script
}
# Handle IPv4 only systems sudo service dovecot restart
if [ ! -f /proc/net/if_inet6 ]; }
then
sudo sed -i 's/^listen.*/listen = \*/' dovecot.conf
fi
FORCE=${2:-0}
DRY_RUN=${3:-0}
safe_copy dovecot.conf /etc/dovecot/dovecot.conf case "$1" in
safe_copy dovecot-ldap.conf /etc/dovecot/dovecot-ldap.conf pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0
# Setup Sieve
sudo mkdir -p /etc/dovecot/global_script
sudo chmod -R 770 /etc/dovecot/global_script
safe_copy dovecot.sieve /etc/dovecot/global_script/dovecot.sieve
sudo chmod 660 /etc/dovecot/global_script/dovecot.sieve > /dev/null 2>&1 \
|| safe_copy dovecot.sieve /etc/dovecot/global_script/dovecot.sieve
sudo sievec /etc/dovecot/global_script/dovecot.sieve
sudo chmod 660 /etc/dovecot/global_script/dovecot.svbin
sudo chown -R vmail:mail /etc/dovecot/global_script
sudo service dovecot restart

92
data/hooks/conf_regen/28-rmilter Normal file → Executable file
View file

@ -1,43 +1,69 @@
set -e #!/bin/bash
force=$1 set -e
function safe_copy () { do_pre_regen() {
if [[ "$force" == "True" ]]; then pending_dir=$1
sudo yunohost service safecopy \
-s rmilter $1 $2 --force cd /usr/share/yunohost/templates/rmilter
else
sudo yunohost service safecopy \ install -D -m 644 rmilter.conf \
-s rmilter $1 $2 "${pending_dir}/etc/rmilter.conf"
fi install -D -m 644 rmilter.socket \
"${pending_dir}/etc/systemd/system/rmilter.socket"
} }
cd /usr/share/yunohost/templates/rmilter do_post_regen() {
regen_conf_files=$1
# Copy Rmilter configuration # retrieve variables
safe_copy rmilter.conf /etc/rmilter.conf domain_list=$(sudo yunohost domain list --output-as plain --quiet)
# Override socket configuration # create DKIM directory
safe_copy rmilter.socket /etc/systemd/system/rmilter.socket sudo mkdir -p /etc/dkim
# Create DKIM key for each YunoHost domain # create DKIM key for domains
sudo mkdir -p /etc/dkim for domain in $domain_list; do
domain_list=$(sudo yunohost domain list --output-as plain) domain_key="/etc/dkim/${domain}.mail.key"
[ ! -f $domain_key ] && {
sudo opendkim-genkey --domain="$domain" \
--selector=mail --directory=/etc/dkim
sudo mv /etc/dkim/mail.private "$domain_key"
sudo mv /etc/dkim/mail.txt "/etc/dkim/${domain}.mail.txt"
}
done
for domain in $domain_list; do # fix DKIM keys permissions
[ -f /etc/dkim/$domain.mail.key ] \ sudo chown _rmilter /etc/dkim/*.mail.key
|| (sudo opendkim-genkey --domain=$domain \ sudo chmod 400 /etc/dkim/*.mail.key
--selector=mail\
--directory=/etc/dkim \
&& sudo mv /etc/dkim/mail.private /etc/dkim/$domain.mail.key \
&& sudo mv /etc/dkim/mail.txt /etc/dkim/$domain.mail.txt)
sudo chown _rmilter /etc/dkim/$domain.mail.key [ -z "$regen_conf_files" ] && exit 0
sudo chmod 400 /etc/dkim/$domain.mail.key
done
# Reload systemd daemon, ensure that the socket is listening and stop # reload systemd daemon
# the service. It will be started again by the socket as needed. [[ "$regen_conf_files" =~ rmilter\.socket ]] && {
sudo systemctl daemon-reload sudo systemctl -q daemon-reload
sudo systemctl start rmilter.socket }
sudo systemctl stop rmilter.service 2>&1 || true
# ensure that the socket is listening and stop the service - it will be
# started again by the socket as needed
sudo systemctl -q start rmilter.socket
sudo systemctl -q stop rmilter.service 2>&1 || true
}
FORCE=${2:-0}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

65
data/hooks/conf_regen/31-rspamd Normal file → Executable file
View file

@ -1,33 +1,50 @@
set -e #!/bin/bash
force=$1 set -e
function safe_copy () { do_pre_regen() {
if [[ "$force" == "True" ]]; then pending_dir=$1
sudo yunohost service safecopy \
-s rspamd $1 $2 --force cd /usr/share/yunohost/templates/rspamd
else
sudo yunohost service safecopy \ install -D -m 644 metrics.local.conf \
-s rspamd $1 $2 "${pending_dir}/etc/rspamd/local.d/metrics.conf"
fi install -D -m 644 rspamd.sieve \
"${pending_dir}/etc/dovecot/global_script/rspamd.sieve"
} }
cd /usr/share/yunohost/templates/rspamd do_post_regen() {
regen_conf_files=$1
# Create configuration directories [ -z "$regen_conf_files" ] && exit 0
sudo mkdir -p /etc/rspamd/local.d /etc/rspamd/override.d
# Copy specific configuration to rewrite the defaults # compile sieve script
safe_copy metrics.conf.local /etc/rspamd/local.d/metrics.conf [[ "$regen_conf_files" =~ rspamd\.sieve ]] && {
sudo sievec /etc/dovecot/global_script/rspamd.sieve
sudo chown -R vmail:mail /etc/dovecot/global_script
sudo systemctl restart dovecot
}
# Install Rspamd sieve script # ensure that the socket is listening and stop the service - it will be
safe_copy rspamd.sieve /etc/dovecot/global_script/rspamd.sieve # started again by the socket as needed
sudo sievec /etc/dovecot/global_script/rspamd.sieve sudo systemctl -q start rspamd.socket
sudo chmod 660 /etc/dovecot/global_script/rspamd.svbin sudo systemctl -q stop rspamd.service 2>&1 || true
sudo chown -R vmail:mail /etc/dovecot/global_script }
# Ensure that the socket is listening and stop the service. FORCE=${2:-0}
sudo systemctl stop rspamd.service 2>&1 || true DRY_RUN=${3:-0}
sudo systemctl start rspamd.socket
sudo systemctl restart dovecot case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

99
data/hooks/conf_regen/34-mysql Normal file → Executable file
View file

@ -1,35 +1,82 @@
#!/bin/bash
set -e set -e
force=$1 do_pre_regen() {
pending_dir=$1
function safe_copy () { cd /usr/share/yunohost/templates/mysql
if [[ "$force" == "True" ]]; then
sudo yunohost service safecopy \ install -D -m 644 my.cnf "${pending_dir}/etc/mysql/my.cnf"
-s mysql $1 $2 --force
else
sudo yunohost service safecopy \
-s mysql $1 $2
fi
} }
function randpass () { do_post_regen() {
[ "$2" == "0" ] && CHAR="[:alnum:]" || CHAR="[:graph:]" regen_conf_files=$1
cat /dev/urandom | tr -cd "$CHAR" | head -c ${1:-32}
echo if [ ! -f /etc/yunohost/mysql ]; then
. /usr/share/yunohost/helpers.d/string
# ensure that mysql is running
service mysql status >/dev/null 2>&1 \
|| service mysql start
# generate and set new root password
mysql_password=$(ynh_string_random 10)
sudo mysqladmin -s -u root -pyunohost password "$mysql_password" || {
if [ $FORCE -eq 1 ]; then
. /usr/share/yunohost/helpers.d/package
echo "It seems that you have already configured MySQL." \
"YunoHost needs to have a root access to MySQL to runs its" \
"applications, and is going to reset the MySQL root password." \
"You can find this new password in /etc/yunohost/mysql." >&2
# retrieve MySQL package provider
ynh_package_is_installed "mariadb-server-10.0" \
&& mysql_pkg="mariadb-server-10.0" \
|| mysql_pkg="mysql-server-5.5"
# set new password with debconf
sudo debconf-set-selections << EOF
$mysql_pkg mysql-server/root_password password $mysql_password
$mysql_pkg mysql-server/root_password_again password $mysql_password
EOF
# reconfigure Debian package
sudo dpkg-reconfigure -freadline -u "$mysql_pkg" 2>&1
else
echo "It seems that you have already configured MySQL." \
"YunoHost needs to have a root access to MySQL to runs its" \
"applications, but the MySQL root password is unknown." \
"You must either pass --force to reset the password or" \
"put the current one into the file /etc/yunohost/mysql." >&2
exit 1
fi
}
# store new root password
echo "$mysql_password" | sudo tee /etc/yunohost/mysql
sudo chmod 400 /etc/yunohost/mysql
fi
[[ -z "$regen_conf_files" ]] \
|| sudo service mysql restart
} }
cd /usr/share/yunohost/templates/mysql FORCE=${2:-0}
DRY_RUN=${3:-0}
if [[ "$(safe_copy my.cnf /etc/mysql/my.cnf | tail -n1)" == "True" ]]; then case "$1" in
sudo service mysql restart pre)
fi do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
if [ ! -f /etc/yunohost/mysql ]; then exit 0
[[ $(/bin/ps aux | grep '[m]ysqld') == "0" ]] \
&& sudo service mysql start
mysql_password=$(randpass 10 0)
sudo mysqladmin -u root -pyunohost password $mysql_password
echo $mysql_password | sudo tee /etc/yunohost/mysql
sudo chmod 400 /etc/yunohost/mysql
fi

46
data/hooks/conf_regen/37-avahi-daemon Normal file → Executable file
View file

@ -1,19 +1,37 @@
set -e #!/bin/bash
force=$1 set -e
function safe_copy () { do_pre_regen() {
if [[ "$force" == "True" ]]; then pending_dir=$1
sudo yunohost service safecopy \
-s avahi-daemon $1 $2 --force cd /usr/share/yunohost/templates/avahi-daemon
else
sudo yunohost service safecopy \ install -D -m 644 avahi-daemon.conf \
-s avahi-daemon $1 $2 "${pending_dir}/etc/avahi/avahi-daemon.conf"
fi
} }
cd /usr/share/yunohost/templates/avahi-daemon do_post_regen() {
regen_conf_files=$1
if [[ "$(safe_copy avahi-daemon.conf /etc/avahi/avahi-daemon.conf | tail -n1)" == "True" ]]; then [[ -z "$regen_conf_files" ]] \
sudo service avahi-daemon restart || sudo service avahi-daemon restart
fi }
FORCE=${2:-0}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

45
data/hooks/conf_regen/40-glances Normal file → Executable file
View file

@ -1,19 +1,36 @@
set -e #!/bin/bash
force=$1 set -e
function safe_copy () { do_pre_regen() {
if [[ "$force" == "True" ]]; then pending_dir=$1
sudo yunohost service safecopy \
-s glances $1 $2 --force cd /usr/share/yunohost/templates/glances
else
sudo yunohost service safecopy \ install -D -m 644 glances.default "${pending_dir}/etc/default/glances"
-s glances $1 $2
fi
} }
cd /usr/share/yunohost/templates/glances do_post_regen() {
regen_conf_files=$1
if [[ "$(safe_copy glances.default /etc/default/glances | tail -n1)" == "True" ]]; then [[ -z "$regen_conf_files" ]] \
sudo service glances restart || sudo service glances restart
fi }
FORCE=${2:-0}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

101
data/hooks/conf_regen/43-dnsmasq Normal file → Executable file
View file

@ -1,53 +1,66 @@
set -e #!/bin/bash
force=$1 set -e
. /usr/share/yunohost/helpers do_pre_regen() {
pending_dir=$1
function safe_copy () { # source ip helpers
if [[ "$force" == "True" ]]; then . /usr/share/yunohost/helpers.d/ip
sudo yunohost service safecopy \
-s dnsmasq $1 $2 --force cd /usr/share/yunohost/templates/dnsmasq
else
sudo yunohost service safecopy \ # create directory for pending conf
-s dnsmasq $1 $2 dnsmasq_dir="${pending_dir}/etc/dnsmasq.d"
fi mkdir -p "$dnsmasq_dir"
# retrieve variables
ipv4=$(curl -s -4 https://ip.yunohost.org 2>/dev/null || true)
ynh_validate_ip4 "$ipv4" || ipv4='127.0.0.1'
ipv6=$(curl -s -6 http://ip6.yunohost.org 2>/dev/null || true)
ynh_validate_ip6 "$ipv6" || ipv6=''
domain_list=$(sudo yunohost domain list --output-as plain --quiet)
# add domain conf files
for domain in $domain_list; do
cat domain.tpl \
| sed "s/{{ domain }}/${domain}/g" \
| sed "s/{{ ip }}/${ipv4}/g" \
> "${dnsmasq_dir}/${domain}"
[[ -n $ipv6 ]] \
&& echo "address=/${domain}/${ipv6}" >> "${dnsmasq_dir}/${domain}"
done
# remove old domain conf files
conf_files=$(ls -1 /etc/dnsmasq.d \
| awk '/^[^\.]+\.[^\.]+.*$/ { print $1 }')
for domain in $conf_files; do
[[ $domain_list =~ $domain ]] \
|| touch "${dnsmasq_dir}/${domain}"
done
} }
cd /usr/share/yunohost/templates/dnsmasq do_post_regen() {
regen_conf_files=$1
# Get IPv4 address [[ -z "$regen_conf_files" ]] \
ip=$(curl -s -4 https://ip.yunohost.org 2>/dev/null || true) || sudo service dnsmasq restart
ynh_validate_ip4 $ip || ip='0.0.0.0' }
# Get IPv6 IP address FORCE=${2:-0}
ipv6=$(curl -s -6 http://ip6.yunohost.org 2>/dev/null || true) DRY_RUN=${3:-0}
ynh_validate_ip6 $ipv6 || ipv6=''
sudo mkdir -p /etc/dnsmasq.d case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
domain_list=$(sudo yunohost domain list --output-as plain) exit 0
# Copy a configuration file for each YunoHost domain
for domain in $domain_list; do
cat domain.sed \
| sed "s/{{ domain }}/$domain/g" \
| sed "s/{{ ip }}/$ip/g" \
| sudo tee $domain
if [[ "$ipv6" != "" ]]; then
echo "address=/$domain/$ipv6" | sudo tee -a $domain
fi
safe_copy $domain /etc/dnsmasq.d/$domain
done
# Remove old domains files
for file in /etc/dnsmasq.d/*.*; do
domain=$(echo $file | sed 's|/etc/dnsmasq.d/||')
[[ $domain_list =~ $domain ]] \
|| sudo yunohost service saferemove -s dnsmasq $file
done
sudo service dnsmasq reload \
|| sudo service dnsmasq restart

45
data/hooks/conf_regen/46-nsswitch Normal file → Executable file
View file

@ -1,19 +1,36 @@
set -e #!/bin/bash
force=$1 set -e
function safe_copy () { do_pre_regen() {
if [[ "$force" == "True" ]]; then pending_dir=$1
sudo yunohost service safecopy \
-s nsswitch $1 $2 --force cd /usr/share/yunohost/templates/nsswitch
else
sudo yunohost service safecopy \ install -D -m 644 nsswitch.conf "${pending_dir}/etc/nsswitch.conf"
-s nsswitch $1 $2
fi
} }
cd /usr/share/yunohost/templates/nsswitch do_post_regen() {
regen_conf_files=$1
if [[ "$(safe_copy nsswitch.conf /etc/nsswitch.conf | tail -n1)" == "True" ]]; then [[ -z "$regen_conf_files" ]] \
sudo service nscd restart || sudo service nscd restart
fi }
FORCE=${2:-0}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

54
data/hooks/conf_regen/52-fail2ban Normal file → Executable file
View file

@ -1,28 +1,40 @@
set -e #!/bin/bash
force=$1 set -e
function safe_copy () { do_pre_regen() {
if [[ "$force" == "True" ]]; then pending_dir=$1
sudo yunohost service safecopy \
-s fail2ban $1 $2 --force cd /usr/share/yunohost/templates/fail2ban
else
sudo yunohost service safecopy \ fail2ban_dir="${pending_dir}/etc/fail2ban"
-s fail2ban $1 $2 mkdir -p "${fail2ban_dir}/filter.d"
fi
cp yunohost.conf "${fail2ban_dir}/filter.d/yunohost.conf"
cp jail.conf "${fail2ban_dir}/jail.conf"
} }
cd /usr/share/yunohost/templates/fail2ban do_post_regen() {
regen_conf_files=$1
sudo mkdir -p /etc/fail2ban/filter.d [[ -z "$regen_conf_files" ]] \
safe_copy yunohost.conf /etc/fail2ban/filter.d/yunohost.conf || sudo service fail2ban restart
}
# Compatibility: change from HDB to MDB on Jessie FORCE=${2:-0}
version=$(sed 's/\..*//' /etc/debian_version) DRY_RUN=${3:-0}
[[ "$version" == '8' ]] \
&& sudo cp jail-jessie.conf jail.conf \
|| sudo cp jail-wheezy.conf jail.conf
if [[ $(safe_copy jail.conf /etc/fail2ban/jail.conf | tail -n1) == "True" ]]; then case "$1" in
sudo service fail2ban restart pre)
fi do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -1,6 +1,42 @@
backup_dir="$1/conf/ynh/mysql" backup_dir="$1/conf/ynh/mysql"
sudo service mysql restart # ensure that mysql is running
sudo cp -a $backup_dir/mysql /etc/yunohost/mysql service mysql status >/dev/null 2>&1 \
mysqlpwd=$(sudo cat /etc/yunohost/mysql) || service mysql start
sudo mysqladmin flush-privileges -p"$mysqlpwd"
# retrieve current and new password
[ -f /etc/yunohost/mysql ] \
&& curr_pwd=$(sudo cat /etc/yunohost/mysql) \
|| curr_pwd="yunohost"
new_pwd=$(sudo cat "${backup_dir}/root_pwd" || sudo cat "${backup_dir}/mysql")
# attempt to change it
sudo mysqladmin -s -u root -p"$curr_pwd" password "$new_pwd" || {
. /usr/share/yunohost/helpers.d/package
echo "It seems that you have already configured MySQL." \
"YunoHost needs to have a root access to MySQL to runs its" \
"applications, and is going to reset the MySQL root password." \
"You can find this new password in /etc/yunohost/mysql." >&2
# retrieve MySQL package provider
ynh_package_is_installed "mariadb-server-10.0" \
&& mysql_pkg="mariadb-server-10.0" \
|| mysql_pkg="mysql-server-5.5"
# set new password with debconf
sudo debconf-set-selections << EOF
$mysql_pkg mysql-server/root_password password $new_pwd
$mysql_pkg mysql-server/root_password_again password $new_pwd
EOF
# reconfigure Debian package
sudo dpkg-reconfigure -freadline -u "$mysql_pkg" 2>&1
}
# store new root password
echo "$new_pwd" | sudo tee /etc/yunohost/mysql
sudo chmod 400 /etc/yunohost/mysql
# reload the grant tables
sudo mysqladmin -s -u root -p"$new_pwd" reload

View file

@ -1 +1,3 @@
backup_dir="$1/conf/ynh"
sudo cp -a "${backup_dir}/current_host" /etc/yunohost/current_host

View file

@ -1,346 +0,0 @@
# Fail2Ban configuration file.
#
# This file was composed for Debian systems from the original one
# provided now under /usr/share/doc/fail2ban/examples/jail.conf
# for additional examples.
#
# To avoid merges during upgrades DO NOT MODIFY THIS FILE
# and rather provide your changes in /etc/fail2ban/jail.local
#
# Author: Yaroslav O. Halchenko <debian@onerussian.com>
#
# $Revision$
#
# The DEFAULT allows a global definition of the options. They can be overridden
# in each jail afterwards.
[DEFAULT]
# "ignoreip" can be an IP address, a CIDR mask or a DNS host
ignoreip = 127.0.0.0/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
bantime = 600
maxretry = 3
# "backend" specifies the backend used to get files modification. Available
# options are "gamin", "polling" and "auto".
# yoh: For some reason Debian shipped python-gamin didn't work as expected
# This issue left ToDo, so polling is default backend for now
backend = auto
#
# Destination email address used solely for the interpolations in
# jail.{conf,local} configuration files.
destemail = root@localhost
#
# ACTIONS
#
# Default banning action (e.g. iptables, iptables-new,
# iptables-multiport, shorewall, etc) It is used to define
# action_* variables. Can be overridden globally or per
# section within jail.local file
banaction = iptables-multiport
# email action. Since 0.8.1 upstream fail2ban uses sendmail
# MTA for the mailing. Change mta configuration parameter to mail
# if you want to revert to conventional 'mail'.
mta = sendmail
# Default protocol
protocol = tcp
# Specify chain where jumps would need to be added in iptables-* actions
chain = INPUT
#
# Action shortcuts. To be used to define action parameter
# The simplest action to take: ban only
action_ = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
# ban & send an e-mail with whois report to the destemail.
action_mw = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois[name=%(__name__)s, dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
# ban & send an e-mail with whois report and relevant log lines
# to the destemail.
action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
# Choose default action. To change, just override value of 'action' with the
# interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local
# globally (section [DEFAULT]) or per specific section
action = %(action_)s
#
# JAILS
#
# Next jails corresponds to the standard configuration in Fail2ban 0.6 which
# was shipped in Debian. Enable any defined here jail by including
#
# [SECTION_NAME]
# enabled = true
#
# in /etc/fail2ban/jail.local.
#
# Optionally you may override any other parameter (e.g. banaction,
# action, port, logpath, etc) in that section within jail.local
[ssh]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 6
[dropbear]
enabled = false
port = ssh
filter = sshd
logpath = /var/log/dropbear
maxretry = 6
# Generic filter for pam. Has to be used with action which bans all ports
# such as iptables-allports, shorewall
[pam-generic]
enabled = false
# pam-generic filter can be customized to monitor specific subset of 'tty's
filter = pam-generic
# port actually must be irrelevant but lets leave it all for some possible uses
port = all
banaction = iptables-allports
port = anyport
logpath = /var/log/auth.log
maxretry = 6
[xinetd-fail]
enabled = false
filter = xinetd-fail
port = all
banaction = iptables-multiport-log
logpath = /var/log/daemon.log
maxretry = 2
[ssh-ddos]
enabled = false
port = ssh
filter = sshd-ddos
logpath = /var/log/auth.log
maxretry = 6
#
# HTTP servers
#
[apache]
enabled = false
port = http,https
filter = apache-auth
logpath = /var/log/apache*/*error.log
maxretry = 6
# default action is now multiport, so apache-multiport jail was left
# for compatibility with previous (<0.7.6-2) releases
[apache-multiport]
enabled = false
port = http,https
filter = apache-auth
logpath = /var/log/apache*/*error.log
maxretry = 6
[apache-noscript]
enabled = false
port = http,https
filter = apache-noscript
logpath = /var/log/apache*/*error.log
maxretry = 6
[apache-overflows]
enabled = false
port = http,https
filter = apache-overflows
logpath = /var/log/apache*/*error.log
maxretry = 2
#
# FTP servers
#
[vsftpd]
enabled = false
port = ftp,ftp-data,ftps,ftps-data
filter = vsftpd
logpath = /var/log/vsftpd.log
# or overwrite it in jails.local to be
# logpath = /var/log/auth.log
# if you want to rely on PAM failed login attempts
# vsftpd's failregex should match both of those formats
maxretry = 6
[proftpd]
enabled = false
port = ftp,ftp-data,ftps,ftps-data
filter = proftpd
logpath = /var/log/proftpd/proftpd.log
maxretry = 6
[pure-ftpd]
enabled = false
port = ftp,ftp-data,ftps,ftps-data
filter = pure-ftpd
logpath = /var/log/auth.log
maxretry = 6
[wuftpd]
enabled = false
port = ftp,ftp-data,ftps,ftps-data
filter = wuftpd
logpath = /var/log/auth.log
maxretry = 6
#
# Mail servers
#
[postfix]
enabled = true
port = smtp,ssmtp
filter = postfix
logpath = /var/log/mail.log
[couriersmtp]
enabled = false
port = smtp,ssmtp
filter = couriersmtp
logpath = /var/log/mail.log
#
# Mail servers authenticators: might be used for smtp,ftp,imap servers, so
# all relevant ports get banned
#
[courierauth]
enabled = false
port = smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s
filter = courierlogin
logpath = /var/log/mail.log
[sasl]
enabled = true
port = smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s
filter = sasl
# You might consider monitoring /var/log/mail.warn instead if you are
# running postfix since it would provide the same log lines at the
# "warn" level but overall at the smaller filesize.
logpath = /var/log/mail.log
[dovecot]
enabled = true
port = smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s
filter = dovecot
logpath = /var/log/mail.log
# DNS Servers
# These jails block attacks against named (bind9). By default, logging is off
# with bind9 installation. You will need something like this:
#
# logging {
# channel security_file {
# file "/var/log/named/security.log" versions 3 size 30m;
# severity dynamic;
# print-time yes;
# };
# category security {
# security_file;
# };
# };
#
# in your named.conf to provide proper logging
# !!! WARNING !!!
# Since UDP is connection-less protocol, spoofing of IP and imitation
# of illegal actions is way too simple. Thus enabling of this filter
# might provide an easy way for implementing a DoS against a chosen
# victim. See
# http://nion.modprobe.de/blog/archives/690-fail2ban-+-dns-fail.html
# Please DO NOT USE this jail unless you know what you are doing.
#[named-refused-udp]
#
#enabled = false
#port = domain,953
#protocol = udp
#filter = named-refused
#logpath = /var/log/named/security.log
[named-refused-tcp]
enabled = false
port = domain,953
protocol = tcp
filter = named-refused
logpath = /var/log/named/security.log
[nginx]
enabled = true
port = http,https
filter = apache-auth
logpath = /var/log/nginx*/*error.log
maxretry = 6
[nginx-noscript]
enabled = false
port = http,https
filter = apache-noscript
logpath = /var/log/nginx*/*error.log
maxretry = 6
[nginx-overflows]
enabled = false
port = http,https
filter = apache-overflows
logpath = /var/log/nginx*/*error.log
maxretry = 4
[yunohost]
enabled = true
port = http,https
protocol = tcp
filter = yunohost
logpath = /var/log/nginx/*.log
maxretry = 6

View file

@ -15,8 +15,13 @@ postfix:
log: [/var/log/mail.log,/var/log/mail.err] log: [/var/log/mail.log,/var/log/mail.err]
rmilter: rmilter:
status: systemctl status rmilter.socket status: systemctl status rmilter.socket
log: /var/log/mail.log
rspamd: rspamd:
status: systemctl status rspamd.socket status: systemctl status rspamd.socket
log: /var/log/mail.log
redis-server:
status: service
log: /var/log/redis/redis-server.log
mysql: mysql:
status: service status: service
log: [/var/log/mysql.log,/var/log/mysql.err] log: [/var/log/mysql.log,/var/log/mysql.err]
@ -39,9 +44,6 @@ yunohost-api:
log: /var/log/yunohost/yunohost-api.log log: /var/log/yunohost/yunohost-api.log
yunohost-firewall: yunohost-firewall:
status: service status: service
postgrey:
status: service
log: /var/log/mail.log
nslcd: nslcd:
status: service status: service
log: /var/log/syslog log: /var/log/syslog
@ -49,3 +51,6 @@ nsswitch:
status: service status: service
udisks2: udisks2:
status: service status: service
amavis: null
postgrey: null
spamassassin: null

39
debian/changelog vendored
View file

@ -1,3 +1,42 @@
yunohost (2.3.12.1) testing; urgency=low
* [deb] Rely on dh_installinit to restart yunohost-firewall after upgrade
* [deb] Add Install section to yunohost-firewall.service
-- Jérôme Lebleu <jerome@yunohost.org> Sat, 09 Apr 2016 17:22:40 +0200
yunohost (2.3.12) testing; urgency=low
[ Jérôme Lebleu ]
* [enh] Use new rspamd configuration system to override metrics
* [enh] Allow to set script execution directory in hook_exec
* [enh] Add a ynh_user_list helper
* [enh] Call app remove script if installation fails
* [fix] Move imports at the top in yunohost and yunohost-api
* [fix] Use rspamd local.d folder to allow users to override the defaults
* [fix] Execute backup/restore app scripts from the backup dir (bugfix #139)
* [fix] Regenerate SSOwat conf after apps restoration
* [fix] Move imports at the top in backup.py
* [fix] Check if the package is actually installed in equivs helper
* [fix] Improve control file management in equivs helper
* [fix] Remove ending comma in backup.py
* [fix] Call yunohost commands with --quiet in setting helpers
* [fix] Check for tty in root_handlers before remove it in bin/yunohost
* [fix] Use dyndns.yunohost.org instead of dynhost.yunohost.org
* [fix] Set found private key and don't validate it in dyndns_update
* [fix] Update first registered domain with DynDNS instead of current_host
* [i18n] Rename app_requirements_failed err named variable
* [i18n] Update translations from Weblate
[ opi ]
* [enh] Better message during service regenconf.
* [enh] Display hook path on error message.
* [enh] Use named arguments when calling m18n in service.py
* [enh] Use named arguments with m18n.
* [enh] Use named arguments for user_unknown string.
-- Jérôme Lebleu <jerome@yunohost.org> Sat, 09 Apr 2016 12:13:10 +0200
moulinette-yunohost (2.2.4) stable; urgency=low moulinette-yunohost (2.2.4) stable; urgency=low
[ Jérôme Lebleu ] [ Jérôme Lebleu ]

4
debian/control vendored
View file

@ -10,7 +10,7 @@ Homepage: https://yunohost.org/
Package: yunohost Package: yunohost
Architecture: all Architecture: all
Depends: ${python:Depends}, ${misc:Depends} Depends: ${python:Depends}, ${misc:Depends}
, moulinette (>= 2.3.4) , moulinette (>= 2.3.5.1)
, python-psutil, python-requests, python-dnspython , python-psutil, python-requests, python-dnspython
, python-apt, python-miniupnpc , python-apt, python-miniupnpc
, glances , glances
@ -27,7 +27,7 @@ Depends: ${python:Depends}, ${misc:Depends}
, rspamd (>= 1.2.0), rmilter (>=1.7.0), redis-server, opendkim-tools , rspamd (>= 1.2.0), rmilter (>=1.7.0), redis-server, opendkim-tools
Recommends: yunohost-admin Recommends: yunohost-admin
, openssh-server, ntp, inetutils-ping | iputils-ping , openssh-server, ntp, inetutils-ping | iputils-ping
, bash-completion, rsyslog , bash-completion, rsyslog, etckeeper
, php5-gd, php5-curl, php-gettext, php5-mcrypt , php5-gd, php5-curl, php-gettext, php5-mcrypt
, python-pip , python-pip
, unattended-upgrades , unattended-upgrades

41
debian/postinst vendored
View file

@ -6,13 +6,13 @@ do_configure() {
rm -rf /var/cache/moulinette/* rm -rf /var/cache/moulinette/*
if [ ! -f /etc/yunohost/installed ]; then if [ ! -f /etc/yunohost/installed ]; then
bash /usr/share/yunohost/hooks/conf_regen/01-yunohost True bash /usr/share/yunohost/hooks/conf_regen/01-yunohost init
bash /usr/share/yunohost/hooks/conf_regen/02-ssl True bash /usr/share/yunohost/hooks/conf_regen/02-ssl init
bash /usr/share/yunohost/hooks/conf_regen/06-slapd True bash /usr/share/yunohost/hooks/conf_regen/06-slapd init
bash /usr/share/yunohost/hooks/conf_regen/15-nginx True bash /usr/share/yunohost/hooks/conf_regen/15-nginx init
else else
echo "Regenerating configuration, this might take a while..." echo "Regenerating configuration, this might take a while..."
yunohost service regenconf yunohost service regen-conf --output-as none
# restart yunohost-firewall if it's running # restart yunohost-firewall if it's running
service yunohost-firewall status >/dev/null \ service yunohost-firewall status >/dev/null \
@ -28,23 +28,18 @@ do_configure() {
restart_yunohost_firewall() { restart_yunohost_firewall() {
echo "Restarting YunoHost firewall..." echo "Restarting YunoHost firewall..."
if [ -x /etc/init.d/yunohost-firewall ]; then
update-rc.d yunohost-firewall defaults >/dev/null || true
if [ -d /run/systemd/system ]; then
systemctl --system daemon-reload >/dev/null || true
else
invoke-rc.d yunohost-firewall start >/dev/null || true
fi
fi
deb-systemd-helper unmask yunohost-firewall.service >/dev/null || true deb-systemd-helper unmask yunohost-firewall.service >/dev/null || true
if deb-systemd-helper --quiet was-enabled yunohost-firewall.service; then if deb-systemd-helper --quiet was-enabled yunohost-firewall.service; then
deb-systemd-helper enable yunohost-firewall.service >/dev/null || true deb-systemd-helper enable yunohost-firewall.service >/dev/null || true
else
deb-systemd-helper update-state yunohost-firewall.service >/dev/null || true
fi fi
deb-systemd-helper update-state yunohost-firewall.service >/dev/null || true
if [ -d /run/systemd/system ]; then if [ -x /etc/init.d/yunohost-firewall ]; then
systemctl --system daemon-reload >/dev/null || true update-rc.d yunohost-firewall enable >/dev/null
deb-systemd-invoke try-restart yunohost-firewall.service >/dev/null || true if [ -n "$2" ]; then
invoke-rc.d yunohost-firewall restart >/dev/null || exit $?
fi
fi fi
} }
@ -71,16 +66,6 @@ case "$1" in
;; ;;
esac esac
# Enable and start yunohost-api sysv service
if [ -x /etc/init.d/yunohost-api ]; then
update-rc.d yunohost-api defaults >/dev/null
if [ -d /run/systemd/system ]; then
systemctl --system daemon-reload >/dev/null || true
else
invoke-rc.d yunohost-api start || exit $?
fi
fi
#DEBHELPER# #DEBHELPER#
exit 0 exit 0

1
debian/postrm vendored
View file

@ -3,7 +3,6 @@
set -e set -e
if [ "$1" = "purge" ]; then if [ "$1" = "purge" ]; then
update-rc.d yunohost-api remove >/dev/null
update-rc.d yunohost-firewall remove >/dev/null update-rc.d yunohost-firewall remove >/dev/null
fi fi

1
debian/prerm vendored
View file

@ -3,7 +3,6 @@
set -e set -e
if [ -x /etc/init.d/yunohost-api ] && ! [ -d /run/systemd/system ]; then if [ -x /etc/init.d/yunohost-api ] && ! [ -d /run/systemd/system ]; then
invoke-rc.d yunohost-api stop || exit $?
invoke-rc.d yunohost-firewall stop || true invoke-rc.d yunohost-firewall stop || true
fi fi

12
debian/rules vendored
View file

@ -8,12 +8,14 @@
dh ${@} --with=python2,systemd dh ${@} --with=python2,systemd
override_dh_installinit: override_dh_installinit:
dh_installinit -pyunohost --name=yunohost-api --noscripts dh_installinit -pyunohost --name=yunohost-api --restart-after-upgrade
dh_installinit -pyunohost --name=yunohost-firewall --noscripts dh_installinit -pyunohost --name=yunohost-firewall --noscripts
override_dh_systemd_enable: override_dh_systemd_enable:
dh_systemd_enable --name=yunohost-api dh_systemd_enable --name=yunohost-api \
dh_systemd_enable --name=yunohost-firewall --no-enable yunohost-api.service
dh_systemd_enable --name=yunohost-firewall --no-enable \
yunohost-firewall.service
override_dh_systemd_start: #override_dh_systemd_start:
dh_systemd_start --restart-after-upgrade yunohost-api.service # dh_systemd_start --restart-after-upgrade yunohost-api.service

View file

@ -9,3 +9,6 @@ ExecStart=/usr/bin/yunohost firewall reload
ExecReload=/usr/bin/yunohost firewall reload ExecReload=/usr/bin/yunohost firewall reload
ExecStop=/usr/bin/yunohost firewall stop ExecStop=/usr/bin/yunohost firewall stop
RemainAfterExit=yes RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

View file

@ -1,213 +1,213 @@
{ {
"action_invalid": "Ungültige Aktion '{:s}'", "action_invalid": "Ungültige Aktion '{action:s}'",
"admin_password": "Verwaltungspasswort", "admin_password": "Verwaltungspasswort",
"admin_password_change_failed": "Passwort kann nicht geändert werden", "admin_password_change_failed": "Passwort kann nicht geändert werden",
"admin_password_changed": "Verwaltungspasswort wurde erfolgreich geändert", "admin_password_changed": "Verwaltungspasswort wurde erfolgreich geändert",
"app_already_installed": "{:s} ist schon installiert", "app_already_installed": "{app:s} ist schon installiert",
"app_argument_choice_invalid": "Invalide Auswahl für Argument '{name:s}'. Muss einer der folgenden Werte sein {choices:s}", "app_argument_choice_invalid": "Invalide Auswahl für Argument '{name:s}'. Muss einer der folgenden Werte sein {choices:s}",
"app_argument_invalid": "Das Argument '{name:s}' hat einen falschen Wert: {error:s}", "app_argument_invalid": "Das Argument '{name:s}' hat einen falschen Wert: {error:s}",
"app_argument_required": "Argument '{name:s}' wird benötigt", "app_argument_required": "Argument '{name:s}' wird benötigt",
"app_extraction_failed": "Installationsdateien konnten nicht entpackt werden", "app_extraction_failed": "Installationsdateien konnten nicht entpackt werden",
"app_id_invalid": "Falsche App ID", "app_id_invalid": "Falsche App ID",
"app_install_files_invalid": "Ungültige Installationsdateien", "app_install_files_invalid": "Ungültige Installationsdateien",
"app_location_already_used": "Eine andere App ist bereits an diesem Ort installiert", "app_location_already_used": "Eine andere App ist bereits an diesem Ort installiert",
"app_location_install_failed": "Die App kann an diesem Ort nicht installiert werden", "app_location_install_failed": "Die App kann an diesem Ort nicht installiert werden",
"app_manifest_invalid": "Ungültiges App Manifest", "app_manifest_invalid": "Ungültiges App Manifest",
"app_no_upgrade": "Keine Aktualisierungen für Apps verfügbar", "app_no_upgrade": "Keine Aktualisierungen für Apps verfügbar",
"app_not_installed": "{:s} ist nicht intalliert", "app_not_installed": "{app:s} ist nicht intalliert",
"app_recent_version_required": "Für {:s} benötigt eine aktuellere Version von moulinette", "app_recent_version_required": "Für {:s} benötigt eine aktuellere Version von moulinette",
"app_removed": "{:s} wurde erfolgreich entfernt", "app_removed": "{app:s} wurde erfolgreich entfernt",
"app_sources_fetch_failed": "Quelldateien konnten nicht abgerufen werden", "app_sources_fetch_failed": "Quelldateien konnten nicht abgerufen werden",
"app_unknown": "Unbekannte App", "app_unknown": "Unbekannte App",
"app_upgrade_failed": "Apps konnten nicht aktualisiert werden", "app_upgrade_failed": "Apps konnten nicht aktualisiert werden",
"app_upgraded": "{:s} wurde erfolgreich aktualisiert", "app_upgraded": "{app:s} wurde erfolgreich aktualisiert",
"appslist_fetched": "Liste der Apps wurde erfolgreich heruntergelanden", "appslist_fetched": "Liste der Apps wurde erfolgreich heruntergelanden",
"appslist_removed": "Appliste erfolgreich entfernt", "appslist_removed": "Appliste erfolgreich entfernt",
"appslist_retrieve_error": "Entfernte App Liste kann nicht gezogen werden", "appslist_retrieve_error": "Entfernte App Liste kann nicht gezogen werden",
"appslist_unknown": "Unbekannte App Liste", "appslist_unknown": "Unbekannte App Liste",
"ask_current_admin_password": "Derzeitiges Verwaltungspasswort", "ask_current_admin_password": "Derzeitiges Verwaltungspasswort",
"ask_email": "E-Mail Adresse", "ask_email": "E-Mail Adresse",
"ask_firstname": "Vorname", "ask_firstname": "Vorname",
"ask_lastname": "Nachname", "ask_lastname": "Nachname",
"ask_list_to_remove": "Liste enternen", "ask_list_to_remove": "Liste enternen",
"ask_main_domain": "Hauptdomain", "ask_main_domain": "Hauptdomain",
"ask_new_admin_password": "Neues Verwaltungskennwort", "ask_new_admin_password": "Neues Verwaltungskennwort",
"ask_password": "Passwort", "ask_password": "Passwort",
"backup_action_required": "Du musst etwas zum Speichern auswählen", "backup_action_required": "Du musst etwas zum Speichern auswählen",
"backup_app_failed": "Konnte keine Sicherung für '{app:s}' erstellen", "backup_app_failed": "Konnte keine Sicherung für '{app:s}' erstellen",
"backup_archive_app_not_found": "App '{app:s}' konnte in keiner Datensicherung gefunden werden", "backup_archive_app_not_found": "App '{app:s}' konnte in keiner Datensicherung gefunden werden",
"backup_archive_hook_not_exec": "Hook '{hook:s}' konnte für diese Datensicherung nicht ausgeführt werden", "backup_archive_hook_not_exec": "Hook '{hook:s}' konnte für diese Datensicherung nicht ausgeführt werden",
"backup_archive_name_exists": "Datensicherung mit dem selben Namen existiert bereits", "backup_archive_name_exists": "Datensicherung mit dem selben Namen existiert bereits",
"backup_archive_name_unknown": "Unbekanntes lokale Datensicherung mit Namen '{name:s}' gefunden", "backup_archive_name_unknown": "Unbekanntes lokale Datensicherung mit Namen '{name:s}' gefunden",
"backup_archive_open_failed": "Kann Sicherungsarchiv nicht öfnen", "backup_archive_open_failed": "Kann Sicherungsarchiv nicht öfnen",
"backup_cleaning_failed": "Verzeichnis von temporäre Sicherungsdaten konnte nicht geleert werden", "backup_cleaning_failed": "Verzeichnis von temporäre Sicherungsdaten konnte nicht geleert werden",
"backup_complete": "Datensicherung komplett", "backup_complete": "Datensicherung komplett",
"backup_creating_archive": "Datensicherung wird erstellt...", "backup_creating_archive": "Datensicherung wird erstellt...",
"backup_delete_error": "Pfad '{path:s}' konnte nicht gelöscht werden", "backup_delete_error": "Pfad '{path:s}' konnte nicht gelöscht werden",
"backup_deleted": "Datensicherung erfolgreich gelöscht", "backup_deleted": "Datensicherung erfolgreich gelöscht",
"backup_extracting_archive": "Entpacke Sicherungsarchiv...", "backup_extracting_archive": "Entpacke Sicherungsarchiv...",
"backup_hook_unknown": "Datensicherungshook '{hook:s}' unbekannt", "backup_hook_unknown": "Datensicherungshook '{hook:s}' unbekannt",
"backup_invalid_archive": "Ungültige Datensicherung", "backup_invalid_archive": "Ungültige Datensicherung",
"backup_nothings_done": "Es gibt keine Änderungen zur Speicherung", "backup_nothings_done": "Es gibt keine Änderungen zur Speicherung",
"backup_output_directory_forbidden": "Verbotenes Ausgabeverzeichnis", "backup_output_directory_forbidden": "Verbotenes Ausgabeverzeichnis",
"backup_output_directory_not_empty": "Ausgabeordner ist nicht leer", "backup_output_directory_not_empty": "Ausgabeordner ist nicht leer",
"backup_output_directory_required": "Für die Datensicherung muss ein Zielverzeichnis angegeben werden", "backup_output_directory_required": "Für die Datensicherung muss ein Zielverzeichnis angegeben werden",
"backup_running_app_script": "Datensicherung für App '{app:s}' wurd durchgeführt...", "backup_running_app_script": "Datensicherung für App '{app:s}' wurd durchgeführt...",
"backup_running_hooks": "Datensicherunghook wird ausgeführt...", "backup_running_hooks": "Datensicherunghook wird ausgeführt...",
"custom_app_url_required": "Es muss eine URL angegeben um deine benutzerdefinierte App {:s} zu aktualisieren", "custom_app_url_required": "Es muss eine URL angegeben um deine benutzerdefinierte App {app:s} zu aktualisieren",
"custom_appslist_name_required": "Du musst einen Namen für deine benutzerdefinierte Appliste angeben", "custom_appslist_name_required": "Du musst einen Namen für deine benutzerdefinierte Appliste angeben",
"dnsmasq_isnt_installed": "dnsmasq scheint nicht installiert zu sein. Bitte führe 'apt-get remove bind9 && apt-get install dnsmasq' aus", "dnsmasq_isnt_installed": "dnsmasq scheint nicht installiert zu sein. Bitte führe 'apt-get remove bind9 && apt-get install dnsmasq' aus",
"domain_cert_gen_failed": "Zertifikat konnte nicht erzeugt werden", "domain_cert_gen_failed": "Zertifikat konnte nicht erzeugt werden",
"domain_created": "Domain erfolgreich erzeugt", "domain_created": "Domain erfolgreich erzeugt",
"domain_creation_failed": "Konnte Domain nicht erzeugen", "domain_creation_failed": "Konnte Domain nicht erzeugen",
"domain_deleted": "Domain erfolgreich gelöscht", "domain_deleted": "Domain erfolgreich gelöscht",
"domain_deletion_failed": "Konnte Domain nicht löschen", "domain_deletion_failed": "Konnte Domain nicht löschen",
"domain_dyndns_already_subscribed": "Du hast dich schon für einen DynDNS-Domain angemeldet", "domain_dyndns_already_subscribed": "Du hast dich schon für einen DynDNS-Domain angemeldet",
"domain_dyndns_invalid": "Domain nicht mittels DynDNS nutzbar", "domain_dyndns_invalid": "Domain nicht mittels DynDNS nutzbar",
"domain_dyndns_root_unknown": "Unbekannte DynDNS Hauptdomain", "domain_dyndns_root_unknown": "Unbekannte DynDNS Hauptdomain",
"domain_exists": "Die Domain existiert bereits", "domain_exists": "Die Domain existiert bereits",
"domain_uninstall_app_first": "Mindestens eine App ist noch für diese Domain installiert. Bitte zuerst die App deinstallieren und erst dann die Domain löschen..", "domain_uninstall_app_first": "Mindestens eine App ist noch für diese Domain installiert. Bitte zuerst die App deinstallieren und erst dann die Domain löschen..",
"domain_unknown": "Unbekannte Domain", "domain_unknown": "Unbekannte Domain",
"domain_zone_exists": "DNS Zonen Datei existiert bereits", "domain_zone_exists": "DNS Zonen Datei existiert bereits",
"domain_zone_not_found": "DNS Zonen Datei kann nicht für Domäne {:s} gefunden werden", "domain_zone_not_found": "DNS Zonen Datei kann nicht für Domäne {:s} gefunden werden",
"done": "Erledigt.", "done": "Erledigt.",
"downloading": "Wird heruntergeladen...", "downloading": "Wird heruntergeladen...",
"dyndns_cron_installed": "DynDNS Cronjob erfolgreich installiert", "dyndns_cron_installed": "DynDNS Cronjob erfolgreich installiert",
"dyndns_cron_remove_failed": "DynDNS Cronjob konnte nicht entfernt werden", "dyndns_cron_remove_failed": "DynDNS Cronjob konnte nicht entfernt werden",
"dyndns_cron_removed": "DynDNS Cronjob wurde erfolgreich gelöscht", "dyndns_cron_removed": "DynDNS Cronjob wurde erfolgreich gelöscht",
"dyndns_ip_update_failed": "IP Adresse konnte nicht für DynDNS aktualisiert werden", "dyndns_ip_update_failed": "IP Adresse konnte nicht für DynDNS aktualisiert werden",
"dyndns_ip_updated": "IP Adresse wurde erfolgreich für DynDNS aktualisiert", "dyndns_ip_updated": "IP Adresse wurde erfolgreich für DynDNS aktualisiert",
"dyndns_key_generating": "DNS Schlüssel wird generiert, das könnte eine Weile dauern...", "dyndns_key_generating": "DNS Schlüssel wird generiert, das könnte eine Weile dauern...",
"dyndns_registered": "DynDNS Domain erfolgreich registriert", "dyndns_registered": "DynDNS Domain erfolgreich registriert",
"dyndns_registration_failed": "DynDNS Domain {:s} konnte nicht registriert werden", "dyndns_registration_failed": "DynDNS Domain konnte nicht registriert werden: {error:s}",
"dyndns_unavailable": "DynDNS Subdomain ist nicht verfügbar", "dyndns_unavailable": "DynDNS Subdomain ist nicht verfügbar",
"executing_command": "Führe Kommendo '{command:s}' aus...", "executing_command": "Führe Kommendo '{command:s}' aus...",
"executing_script": "Skript '{script:s}' wird ausgeührt...", "executing_script": "Skript '{script:s}' wird ausgeührt...",
"extracting": "Wird entpackt...", "extracting": "Wird entpackt...",
"field_invalid": "Feld '{:s}' ist unbekannt", "field_invalid": "Feld '{:s}' ist unbekannt",
"firewall_reload_failed": "Firewall konnte nicht neu geladen werden", "firewall_reload_failed": "Firewall konnte nicht neu geladen werden",
"firewall_reloaded": "Firewall erfolgreich neu geladen", "firewall_reloaded": "Firewall erfolgreich neu geladen",
"firewall_rules_cmd_failed": "Einzelne Firewallregeln konnten nicht übernommen werden. Mehr Informationen sind im Log zu finden.", "firewall_rules_cmd_failed": "Einzelne Firewallregeln konnten nicht übernommen werden. Mehr Informationen sind im Log zu finden.",
"format_datetime_short": "%m/%d/%Y %I:%M %p", "format_datetime_short": "%m/%d/%Y %I:%M %p",
"hook_argument_missing": "Fehlend Argument '{:s}'", "hook_argument_missing": "Fehlend Argument '{:s}'",
"hook_choice_invalid": "ungültige Wahl '{:s}'", "hook_choice_invalid": "ungültige Wahl '{:s}'",
"hook_exec_failed": "Skriptausführung fehlgeschlagen", "hook_exec_failed": "Skriptausführung fehlgeschlagen",
"hook_exec_not_terminated": "Skriptausführung noch nicht beendet", "hook_exec_not_terminated": "Skriptausführung noch nicht beendet",
"hook_list_by_invalid": "Ungültiger Wert zur Anzeige von Hooks", "hook_list_by_invalid": "Ungültiger Wert zur Anzeige von Hooks",
"hook_name_unknown": "Hook '{:s}' ist nicht bekannt", "hook_name_unknown": "Hook '{name:s}' ist nicht bekannt",
"installation_complete": "Installation vollständig", "installation_complete": "Installation vollständig",
"installation_failed": "Installation fehlgeschlagen", "installation_failed": "Installation fehlgeschlagen",
"ip6tables_unavailable": "ip6tables kann nicht verwendet werden. Du befindest dich entweder in einem Container, oder es wird nicht vom Kernel unterstützt.", "ip6tables_unavailable": "ip6tables kann nicht verwendet werden. Du befindest dich entweder in einem Container, oder es wird nicht vom Kernel unterstützt.",
"iptables_unavailable": "iptables kann nicht verwendet werden. Du befindest dich entweder in einem Container, oder es wird nicht vom Kernel unterstützt.", "iptables_unavailable": "iptables kann nicht verwendet werden. Du befindest dich entweder in einem Container, oder es wird nicht vom Kernel unterstützt.",
"ldap_initialized": "LDAP erfolgreich initialisiert", "ldap_initialized": "LDAP erfolgreich initialisiert",
"license_undefined": "Undeiniert", "license_undefined": "Undeiniert",
"mail_alias_remove_failed": "E-Mail Alias '{:s}' konnte nicht entfernt werden", "mail_alias_remove_failed": "E-Mail Alias '{mail:s}' konnte nicht entfernt werden",
"mail_domain_unknown": "Unbekannte Mail Domain '{:s}'", "mail_domain_unknown": "Unbekannte Mail Domain '{domain:s}'",
"mail_forward_remove_failed": "Mailweiterleitung '{:s}' konnte nicht entfernt werden", "mail_forward_remove_failed": "Mailweiterleitung '{mail:s}' konnte nicht entfernt werden",
"maindomain_change_failed": "Hauptdomain konnte nicht geändert werden", "maindomain_change_failed": "Hauptdomain konnte nicht geändert werden",
"maindomain_changed": "Hauptdomain wurde erfolgreich geändert", "maindomain_changed": "Hauptdomain wurde erfolgreich geändert",
"monitor_disabled": "Servermonitoring erfolgreich deaktiviert", "monitor_disabled": "Servermonitoring erfolgreich deaktiviert",
"monitor_enabled": "Servermonitoring erfolgreich aktiviert", "monitor_enabled": "Servermonitoring erfolgreich aktiviert",
"monitor_glances_con_failed": "Verbindung mit Glances nicht möglich", "monitor_glances_con_failed": "Verbindung mit Glances nicht möglich",
"monitor_not_enabled": "Servermonitoring ist nicht aktiviert", "monitor_not_enabled": "Servermonitoring ist nicht aktiviert",
"monitor_period_invalid": "Falscher Zeitraum", "monitor_period_invalid": "Falscher Zeitraum",
"monitor_stats_file_not_found": "Statistikdatei nicht gefunden", "monitor_stats_file_not_found": "Statistikdatei nicht gefunden",
"monitor_stats_no_update": "Keine Monitoringstatistik zur Aktualisierung", "monitor_stats_no_update": "Keine Monitoringstatistik zur Aktualisierung",
"monitor_stats_period_unavailable": "Keine Statistiken für den gewählten Zeitraum verfügbar", "monitor_stats_period_unavailable": "Keine Statistiken für den gewählten Zeitraum verfügbar",
"mountpoint_unknown": "Unbekannten Einhängepunkt", "mountpoint_unknown": "Unbekannten Einhängepunkt",
"mysql_db_creation_failed": "MySQL Datenbankerzeugung fehlgeschlagen", "mysql_db_creation_failed": "MySQL Datenbankerzeugung fehlgeschlagen",
"mysql_db_init_failed": "MySQL Datenbankinitialisierung fehlgeschlagen", "mysql_db_init_failed": "MySQL Datenbankinitialisierung fehlgeschlagen",
"mysql_db_initialized": "MySQL Datenbank erfolgreich initialisiert", "mysql_db_initialized": "MySQL Datenbank erfolgreich initialisiert",
"network_check_mx_ko": "Es ist kein DNS MX Eintrag vorhanden", "network_check_mx_ko": "Es ist kein DNS MX Eintrag vorhanden",
"network_check_smtp_ko": "Ausgehender Mailverkehr (SMTP Port 25) scheint in deinem Netzwerk blockiert zu sein", "network_check_smtp_ko": "Ausgehender Mailverkehr (SMTP Port 25) scheint in deinem Netzwerk blockiert zu sein",
"network_check_smtp_ok": "Ausgehender Mailverkehr (SMTP Port 25) ist blockiert", "network_check_smtp_ok": "Ausgehender Mailverkehr (SMTP Port 25) ist blockiert",
"new_domain_required": "Du musst eine neue Hauptdomain angeben", "new_domain_required": "Du musst eine neue Hauptdomain angeben",
"no_appslist_found": "Keine Appliste gefunden", "no_appslist_found": "Keine Appliste gefunden",
"no_internet_connection": "Der Server ist nicht mit dem Internet verbunden", "no_internet_connection": "Der Server ist nicht mit dem Internet verbunden",
"no_ipv6_connectivity": "Eine IPv6 Verbindung steht nicht zur Verfügung", "no_ipv6_connectivity": "Eine IPv6 Verbindung steht nicht zur Verfügung",
"no_restore_script": "Es konnte kein Wiederherstellungsskript für '{app:s}' gefunden werden", "no_restore_script": "Es konnte kein Wiederherstellungsskript für '{app:s}' gefunden werden",
"no_such_conf_file": "Datei {file:s}: konnte nicht kopiert werden, da diese nicht existiert", "no_such_conf_file": "Datei {file:s}: konnte nicht kopiert werden, da diese nicht existiert",
"packages_no_upgrade": "Es müssen keine Pakete aktualisiert werden", "packages_no_upgrade": "Es müssen keine Pakete aktualisiert werden",
"packages_upgrade_critical_later": "Wichtiges Paket ({:s}) wird später aktualisiert", "packages_upgrade_critical_later": "Wichtiges Paket ({packages:s}) wird später aktualisiert",
"packages_upgrade_failed": "Es konnten nicht alle Pakete aktualisiert werden", "packages_upgrade_failed": "Es konnten nicht alle Pakete aktualisiert werden",
"path_removal_failed": "Pfad {:s} konnte nicht entfernt werden", "path_removal_failed": "Pfad {:s} konnte nicht entfernt werden",
"pattern_backup_archive_name": "Ein gültiger Dateiname kann nur aus alphanumerischen und -_. bestehen", "pattern_backup_archive_name": "Ein gültiger Dateiname kann nur aus alphanumerischen und -_. bestehen",
"pattern_domain": "Muss ein gültiger Domainname sein (z.B. meine-domain.org)", "pattern_domain": "Muss ein gültiger Domainname sein (z.B. meine-domain.org)",
"pattern_email": "Muss eine gültige E-Mail Adresse sein (z.B. someone@domain.org)", "pattern_email": "Muss eine gültige E-Mail Adresse sein (z.B. someone@domain.org)",
"pattern_firstname": "Muss ein gültiger Vorname sein", "pattern_firstname": "Muss ein gültiger Vorname sein",
"pattern_lastname": "Muss ein gültiger Nachname sein", "pattern_lastname": "Muss ein gültiger Nachname sein",
"pattern_listname": "Kann nur Alphanumerische Zeichen oder Unterstriche enthalten", "pattern_listname": "Kann nur Alphanumerische Zeichen oder Unterstriche enthalten",
"pattern_mailbox_quota": "Muss eine Größe inkl. b/k/M/G/T Suffix, oder 0 zum deaktivieren sein", "pattern_mailbox_quota": "Muss eine Größe inkl. b/k/M/G/T Suffix, oder 0 zum deaktivieren sein",
"pattern_password": "Muss mindestens drei Zeichen lang sein", "pattern_password": "Muss mindestens drei Zeichen lang sein",
"pattern_port": "Es muss ein valider Port (zwischen 0 und 65535) angegeben werden", "pattern_port": "Es muss ein valider Port (zwischen 0 und 65535) angegeben werden",
"pattern_port_or_range": "Muss ein valider Port (z.B. 0-65535) oder ein Bereich (z.B. 100:200) sein", "pattern_port_or_range": "Muss ein valider Port (z.B. 0-65535) oder ein Bereich (z.B. 100:200) sein",
"pattern_username": "Darf nur aus klein geschriebenen alphanumerischen Zeichen und Unterstrichen bestehen", "pattern_username": "Darf nur aus klein geschriebenen alphanumerischen Zeichen und Unterstrichen bestehen",
"port_already_closed": "Port {} wurde bereits für {:s} Verbindungen geschlossen", "port_already_closed": "Port {port:d} wurde bereits für {ip_version:s} Verbindungen geschlossen",
"port_already_opened": "Der Port {} wird bereits von {:s} benutzt", "port_already_opened": "Der Port {port:d} wird bereits von {ip_version:s} benutzt",
"port_available": "Port {} ist verfügbar", "port_available": "Port {port:d} ist verfügbar",
"port_unavailable": "Der Port {} ist nicht verfügbar", "port_unavailable": "Der Port {port:d} ist nicht verfügbar",
"restore_action_required": "Du musst etwas zum Wiederherstellen auswählen", "restore_action_required": "Du musst etwas zum Wiederherstellen auswählen",
"restore_already_installed_app": "Es ist bereits eine App mit der ID '{app:s}' installiet", "restore_already_installed_app": "Es ist bereits eine App mit der ID '{app:s}' installiet",
"restore_app_failed": "App '{app:s}' konnte nicht wiederhergestellt werden", "restore_app_failed": "App '{app:s}' konnte nicht wiederhergestellt werden",
"restore_cleaning_failed": "Temporäres Wiederherstellungsverzeichnis konnte nicht geleert werden", "restore_cleaning_failed": "Temporäres Wiederherstellungsverzeichnis konnte nicht geleert werden",
"restore_complete": "Wiederherstellung abgeschlossen", "restore_complete": "Wiederherstellung abgeschlossen",
"restore_confirm_yunohost_installed": "Möchtest du die Wiederherstellung wirklich starten? [{answers:s}]", "restore_confirm_yunohost_installed": "Möchtest du die Wiederherstellung wirklich starten? [{answers:s}]",
"restore_failed": "System kann nicht Wiederhergestellt werden", "restore_failed": "System kann nicht Wiederhergestellt werden",
"restore_hook_unavailable": "Der Wiederherstellungshook '{hook:s}' steht auf deinem System nicht zur Verfügung", "restore_hook_unavailable": "Der Wiederherstellungshook '{hook:s}' steht auf deinem System nicht zur Verfügung",
"restore_nothings_done": "Es wurde nicht wiederhergestellt", "restore_nothings_done": "Es wurde nicht wiederhergestellt",
"restore_running_app_script": "Wiederherstellung wird ausfeührt für App '{app:s}'...", "restore_running_app_script": "Wiederherstellung wird ausfeührt für App '{app:s}'...",
"restore_running_hooks": "Wiederherstellung wird gestartet...", "restore_running_hooks": "Wiederherstellung wird gestartet...",
"service_add_configuration": "Füge Konfigurationsdatei {file:s} hinzu", "service_add_configuration": "Füge Konfigurationsdatei {file:s} hinzu",
"service_add_failed": "Dienst '{:s}' kann nicht hinzugefügt werden", "service_add_failed": "Dienst '{service:s}' kann nicht hinzugefügt werden",
"service_added": "Service erfolgreich hinzugefügt", "service_added": "Service erfolgreich hinzugefügt",
"service_already_started": "Der Dienst '{:s}' läutt bereits", "service_already_started": "Der Dienst '{service:s}' läutt bereits",
"service_already_stopped": "Dienst '{:s}' wurde bereits gestoppt", "service_already_stopped": "Dienst '{service:s}' wurde bereits gestoppt",
"service_cmd_exec_failed": "Kommando '{:s}' kann nicht ausgeführt werden", "service_cmd_exec_failed": "Kommando '{command:s}' kann nicht ausgeführt werden",
"service_configuration_conflict": "Die Datei {file:s} wurde zwischenzeitlich verändert. Bitte übernehme die Änderungen manuell oder nutze die Option --force (diese wird alle Änderungen überschreiben).", "service_configuration_conflict": "Die Datei {file:s} wurde zwischenzeitlich verändert. Bitte übernehme die Änderungen manuell oder nutze die Option --force (diese wird alle Änderungen überschreiben).",
"service_disable_failed": "Dienst'{:s}' konnte nicht deaktiviert werden", "service_disable_failed": "Dienst '{service:s}' konnte nicht deaktiviert werden",
"service_disabled": "Der Dienst '{:s}' wurde erfolgreich deaktiviert", "service_disabled": "Der Dienst '{service:s}' wurde erfolgreich deaktiviert",
"service_enable_failed": "Dienst '{:s}' konnte nicht aktiviert werden", "service_enable_failed": "Dienst '{service:s}' konnte nicht aktiviert werden",
"service_enabled": "Dienst '{:s}' erfolgreich aktiviert", "service_enabled": "Dienst '{service:s}' erfolgreich aktiviert",
"service_no_log": "Für den Dienst '{:s}' kann kein Log angezeigt werden", "service_no_log": "Für den Dienst '{service:s}' kann kein Log angezeigt werden",
"service_remove_failed": "Dienst '{:s}' konnte nicht entfernt werden", "service_remove_failed": "Dienst '{service:s}' konnte nicht entfernt werden",
"service_removed": "Dienst erfolgreich enternt", "service_removed": "Dienst erfolgreich enternt",
"service_start_failed": "Dienst '{:s}' konnte nicht gestartet werden", "service_start_failed": "Dienst '{service:s}' konnte nicht gestartet werden",
"service_started": "der Dienst '{:s}' wurde erfolgreich gestartet", "service_started": "der Dienst '{service:s}' wurde erfolgreich gestartet",
"service_status_failed": "Status von '{:s}' kann nicht festgestellt werden", "service_status_failed": "Status von '{service:s}' kann nicht festgestellt werden",
"service_stop_failed": "Dienst '{:s}' kann nicht gestoppt werden", "service_stop_failed": "Dienst '{service:s}' kann nicht gestoppt werden",
"service_stopped": "Dienst '{:s}' wurde erfolgreich beendet", "service_stopped": "Dienst '{service:s}' wurde erfolgreich beendet",
"service_unknown": "Unbekannte Dienst '{:s}'", "service_unknown": "Unbekannte Dienst '{service:s}'",
"services_configured": "Konfiguration erfolgreich erstellt", "services_configured": "Konfiguration erfolgreich erstellt",
"show_diff": "Es gibt folgende Änderungen:\n{diff:s}", "show_diff": "Es gibt folgende Änderungen:\n{diff:s}",
"ssowat_conf_generated": "Konfiguration von SSOwat erfolgreich", "ssowat_conf_generated": "Konfiguration von SSOwat erfolgreich",
"ssowat_conf_updated": "Persistente SSOwat Einstellung erfolgreich aktualisiert", "ssowat_conf_updated": "Persistente SSOwat Einstellung erfolgreich aktualisiert",
"system_upgraded": "System wurde erfolgreich aktualisiert", "system_upgraded": "System wurde erfolgreich aktualisiert",
"system_username_exists": "Der Benutzername existiert bereits", "system_username_exists": "Der Benutzername existiert bereits",
"unbackup_app": "App '{app:s}' konnte nicht gespeichert werden", "unbackup_app": "App '{app:s}' konnte nicht gespeichert werden",
"unexpected_error": "Ein unerwarteter Fehler ist aufgetreten", "unexpected_error": "Ein unerwarteter Fehler ist aufgetreten",
"unit_unknown": "Unbekannte Einheit '{:s}'", "unit_unknown": "Unbekannte Einheit '{unit:s}'",
"unlimit": "Kein Kontingent", "unlimit": "Kein Kontingent",
"unrestore_app": "App '{app:s}' kann nicht Wiederhergestellt werden", "unrestore_app": "App '{app:s}' kann nicht Wiederhergestellt werden",
"update_cache_failed": "Konnte APT cache nicht aktualisieren", "update_cache_failed": "Konnte APT cache nicht aktualisieren",
"updating_apt_cache": "Liste der verfügbaren Pakete wird aktualisiert...", "updating_apt_cache": "Liste der verfügbaren Pakete wird aktualisiert...",
"upgrade_complete": "Upgrade vollständig", "upgrade_complete": "Upgrade vollständig",
"upgrading_packages": "Pakete werden aktualisiert...", "upgrading_packages": "Pakete werden aktualisiert...",
"upnp_dev_not_found": "Es konnten keine UPnP Geräte gefunden werden", "upnp_dev_not_found": "Es konnten keine UPnP Geräte gefunden werden",
"upnp_disabled": "UPnP wurde erfolgreich deaktiviert", "upnp_disabled": "UPnP wurde erfolgreich deaktiviert",
"upnp_enabled": "UPnP wurde aktiviert", "upnp_enabled": "UPnP wurde aktiviert",
"upnp_port_open_failed": "UPnP Ports konnten nicht geöffnet werden", "upnp_port_open_failed": "UPnP Ports konnten nicht geöffnet werden",
"user_created": "Benutzer erfolgreich erstellt", "user_created": "Benutzer erfolgreich erstellt",
"user_creation_failed": "Nutzer konnte nicht erstellt werden", "user_creation_failed": "Nutzer konnte nicht erstellt werden",
"user_deleted": "Benutzer wurde erfolgreich entfernt", "user_deleted": "Benutzer wurde erfolgreich entfernt",
"user_deletion_failed": "Nutzer konnte nicht gelöscht werden", "user_deletion_failed": "Nutzer konnte nicht gelöscht werden",
"user_home_creation_failed": "Benutzer Home konnte nicht erstellt werden", "user_home_creation_failed": "Benutzer Home konnte nicht erstellt werden",
"user_info_failed": "Nutzerinformationen können nicht angezeigt werden", "user_info_failed": "Nutzerinformationen können nicht angezeigt werden",
"user_unknown": "Unbekannter Benutzer", "user_unknown": "Unbekannter Benutzer",
"user_update_failed": "Benutzer kann nicht aktualisiert werden", "user_update_failed": "Benutzer kann nicht aktualisiert werden",
"user_updated": "Benutzer wurde erfolgreich aktualisiert", "user_updated": "Benutzer wurde erfolgreich aktualisiert",
"yunohost_already_installed": "YunoHost ist bereits installiert", "yunohost_already_installed": "YunoHost ist bereits installiert",
"yunohost_ca_creation_failed": "Zertifikatsstelle konnte nicht erstellt werden", "yunohost_ca_creation_failed": "Zertifikatsstelle konnte nicht erstellt werden",
"yunohost_configured": "YunoHost wurde erfolgreich konfiguriert", "yunohost_configured": "YunoHost wurde erfolgreich konfiguriert",
"yunohost_installing": "YunoHost wird installiert...", "yunohost_installing": "YunoHost wird installiert...",
"yunohost_not_installed": "Die YunoHost ist unvollständig. Bitte 'yunohost tools postinstall' ausführen." "yunohost_not_installed": "Die YunoHost ist unvollständig. Bitte 'yunohost tools postinstall' ausführen."
} }

View file

@ -22,7 +22,7 @@
"custom_app_url_required" : "You must provide an URL to upgrade your custom app {app:s}", "custom_app_url_required" : "You must provide an URL to upgrade your custom app {app:s}",
"app_requirements_checking" : "Checking required packages...", "app_requirements_checking" : "Checking required packages...",
"app_requirements_unmeet" : "Requirements are not met, the package {pkgname} ({version}) must be {spec}", "app_requirements_unmeet" : "Requirements are not met, the package {pkgname} ({version}) must be {spec}",
"app_requirements_failed" : "Unable to meet requirements: {err}", "app_requirements_failed" : "Unable to meet requirements: {error}",
"app_upgraded" : "{app:s} successfully upgraded", "app_upgraded" : "{app:s} successfully upgraded",
"app_upgrade_failed" : "Unable to upgrade {app:s}", "app_upgrade_failed" : "Unable to upgrade {app:s}",
"app_id_invalid" : "Invalid app id", "app_id_invalid" : "Invalid app id",
@ -34,6 +34,8 @@
"app_extraction_failed" : "Unable to extract installation files", "app_extraction_failed" : "Unable to extract installation files",
"app_install_files_invalid" : "Invalid installation files", "app_install_files_invalid" : "Invalid installation files",
"app_manifest_invalid" : "Invalid app manifest", "app_manifest_invalid" : "Invalid app manifest",
"app_incompatible" : "The app is incompatible with your YunoHost version",
"app_package_need_update" : "The app package need to be updated to follow YunoHost changes",
"app_argument_choice_invalid" : "Invalid choice for argument '{name:s}', it must be one of {choices:s}", "app_argument_choice_invalid" : "Invalid choice for argument '{name:s}', it must be one of {choices:s}",
"app_argument_invalid" : "Invalid value for argument '{name:s}': {error:s}", "app_argument_invalid" : "Invalid value for argument '{name:s}': {error:s}",
"app_argument_required" : "Argument '{name:s}' is required", "app_argument_required" : "Argument '{name:s}' is required",
@ -128,12 +130,20 @@
"service_status_failed" : "Unable to determine status of service '{service:s}'", "service_status_failed" : "Unable to determine status of service '{service:s}'",
"service_no_log" : "No log to display for service '{service:s}'", "service_no_log" : "No log to display for service '{service:s}'",
"service_cmd_exec_failed" : "Unable to execute command '{command:s}'", "service_cmd_exec_failed" : "Unable to execute command '{command:s}'",
"service_configured": "Configuration successfully generated for service '{service:s}'", "service_regenconf_failed" : "Unable to regenerate the configuration for service(s): {services}",
"service_configured_all": "Configuration successfully generated for every services", "service_regenconf_pending_applying" : "Applying pending configuration for service '{service}'...",
"service_configuration_conflict": "The file {file:s} has been changed since its last generation. Please apply the modifications manually or use the option --force (it will erase all the modifications previously done to the file).", "service_regenconf_dry_pending_applying" : "Checking pending configuration which would have been applied for service '{service}'...",
"no_such_conf_file": "Unable to copy the file {file:s}: the file does not exist", "service_conf_file_manually_removed" : "The configuration file '{conf}' has been manually removed and will not be created",
"service_add_configuration": "Adding the configuration file {file:s}", "service_conf_file_manually_modified" : "The configuration file '{conf}' has been manually modified and will not be updated",
"show_diff": "Here are the differences:\n{diff:s}", "service_conf_file_not_managed" : "The configuration file '{conf}' is not managed yet and will not be updated",
"service_conf_file_backed_up" : "The configuration file '{conf}' has been backed up to '{backup}'",
"service_conf_file_removed" : "The configuration file '{conf}' has been removed",
"service_conf_file_remove_failed" : "Unable to remove the configuration file '{conf}'",
"service_conf_file_updated" : "The configuration file '{conf}' has been updated",
"service_conf_file_copy_failed" : "Unable to copy the new configuration file '{new}' to '{conf}'",
"service_conf_up_to_date" : "The configuration is already up-to-date for service '{service}'",
"service_conf_updated" : "The configuration has been updated for service '{service}'",
"service_conf_would_be_updated" : "The configuration would have been updated for service '{service}'",
"network_check_smtp_ok" : "Outbound mail (SMTP port 25) is not blocked", "network_check_smtp_ok" : "Outbound mail (SMTP port 25) is not blocked",
"network_check_smtp_ko" : "Outbound mail (SMTP port 25) seems to be blocked by your network", "network_check_smtp_ko" : "Outbound mail (SMTP port 25) seems to be blocked by your network",

View file

@ -1,9 +1,9 @@
{ {
"action_invalid": "Acción inválida '{:s}'", "action_invalid": "Acción inválida '{action:s}'",
"admin_password": "Contraseña administrativa", "admin_password": "Contraseña administrativa",
"admin_password_change_failed": "No se pudo cambiar la contraseña", "admin_password_change_failed": "No se pudo cambiar la contraseña",
"admin_password_changed": "Contraseña administrativa se cambió con éxito", "admin_password_changed": "Contraseña administrativa se cambió con éxito",
"app_already_installed": "{:s} ya está instalado ", "app_already_installed": "{app:s} ya está instalado",
"app_extraction_failed": "No se pudo extraer los archivos de instalación ", "app_extraction_failed": "No se pudo extraer los archivos de instalación ",
"app_id_invalid": "id de la aplicación inválida ", "app_id_invalid": "id de la aplicación inválida ",
"app_install_files_invalid": "Archivos de instalación inválidos ", "app_install_files_invalid": "Archivos de instalación inválidos ",
@ -11,13 +11,13 @@
"app_location_install_failed": "No se pudo instalar la aplicación en esta lugar", "app_location_install_failed": "No se pudo instalar la aplicación en esta lugar",
"app_manifest_invalid": "Manifesto de la aplicación es inválido", "app_manifest_invalid": "Manifesto de la aplicación es inválido",
"app_no_upgrade": "Ninguna app a actualizar", "app_no_upgrade": "Ninguna app a actualizar",
"app_not_installed": "{:s} no está instalado.", "app_not_installed": "{app:s} no está instalado",
"app_recent_version_required": "{:s} requiere una versión más reciente de moulinette ", "app_recent_version_required": "{:s} requiere una versión más reciente de moulinette ",
"app_removed": "{:s} era eliminado con éxito ", "app_removed": "{app:s} era eliminado con éxito",
"app_sources_fetch_failed": "No se pudo descargar los archivos de códigos fuentes", "app_sources_fetch_failed": "No se pudo descargar los archivos de códigos fuentes",
"app_unknown": "App desconocida", "app_unknown": "App desconocida",
"app_upgrade_failed": "No se pudo actualizar todas las aplicaciones ", "app_upgrade_failed": "No se pudo actualizar todas las aplicaciones ",
"app_upgraded": "{:s} actualizado con éxito", "app_upgraded": "{app:s} actualizado con éxito",
"appslist_fetched": "Lista de aplicaciones se trajo con éxito", "appslist_fetched": "Lista de aplicaciones se trajo con éxito",
"appslist_removed": "Lista de aplicaciones se eliminó con éxito", "appslist_removed": "Lista de aplicaciones se eliminó con éxito",
"appslist_retrieve_error": "No se pudo recuperar la lista de aplicaciones a distancia ", "appslist_retrieve_error": "No se pudo recuperar la lista de aplicaciones a distancia ",
@ -41,7 +41,7 @@
"backup_output_directory_not_empty": "La carpeta de salida no está vacía", "backup_output_directory_not_empty": "La carpeta de salida no está vacía",
"backup_output_directory_required": "Debe proporcionar un directorio de salida para el backup", "backup_output_directory_required": "Debe proporcionar un directorio de salida para el backup",
"backup_running_hooks": "Ejecutando los hooks de backup...", "backup_running_hooks": "Ejecutando los hooks de backup...",
"custom_app_url_required": " Debe proporcionar una URL para actualizar su aplicación personalizada {:s} ", "custom_app_url_required": "Debe proporcionar una URL para actualizar su aplicación personalizada {app:s}",
"custom_appslist_name_required": "Debe proporcionar un nombre para la lista de aplicaciones personalizadas ", "custom_appslist_name_required": "Debe proporcionar un nombre para la lista de aplicaciones personalizadas ",
"dnsmasq_isnt_installed": "Parece que dnsmasq no está instalado, por favor, ejecuta 'apt-get remove bind9 && apt-get install dnsmasq'", "dnsmasq_isnt_installed": "Parece que dnsmasq no está instalado, por favor, ejecuta 'apt-get remove bind9 && apt-get install dnsmasq'",
"domain_cert_gen_failed": "No se pudo crear certificado", "domain_cert_gen_failed": "No se pudo crear certificado",
@ -66,7 +66,7 @@
"dyndns_ip_updated": "La dirección IP era actualizado en DynDNS con éxito", "dyndns_ip_updated": "La dirección IP era actualizado en DynDNS con éxito",
"dyndns_key_generating": "Generación del llave de DNS está en curso. Este podría durar unos momentos...", "dyndns_key_generating": "Generación del llave de DNS está en curso. Este podría durar unos momentos...",
"dyndns_registered": "El dominio DynDNS era registrado con éxito.", "dyndns_registered": "El dominio DynDNS era registrado con éxito.",
"dyndns_registration_failed": "No se pudo registrar el dominio DynDNS: {:s}", "dyndns_registration_failed": "No se pudo registrar el dominio DynDNS: {error:s}",
"dyndns_unavailable": "Subdominio DynDNS no disponible", "dyndns_unavailable": "Subdominio DynDNS no disponible",
"executing_script": "Ejecutando script...", "executing_script": "Ejecutando script...",
"extracting": "Extrayendo...", "extracting": "Extrayendo...",
@ -77,16 +77,16 @@
"hook_argument_missing": "Falta un parámetro '{:s}'", "hook_argument_missing": "Falta un parámetro '{:s}'",
"hook_choice_invalid": "Selección inválida '{:s}'", "hook_choice_invalid": "Selección inválida '{:s}'",
"hook_list_by_invalid": "La propiedad de este hook es inválida", "hook_list_by_invalid": "La propiedad de este hook es inválida",
"hook_name_unknown": "Hook desconocido '{:s}'", "hook_name_unknown": "Hook desconocido '{name:s}'",
"installation_complete": "La instalación se ha completado", "installation_complete": "La instalación se ha completado",
"installation_failed": "La Instalación se ha fracasado", "installation_failed": "La Instalación se ha fracasado",
"ip6tables_unavailable": "No puedes modificar los ip6tables aquí. Eres en un contenedor o su kernel no soporte este opción.", "ip6tables_unavailable": "No puedes modificar los ip6tables aquí. Eres en un contenedor o su kernel no soporte este opción.",
"iptables_unavailable": "No puedes modificar los iptables aquí. Eres en un contenedor o su kernel no soporte este opción.", "iptables_unavailable": "No puedes modificar los iptables aquí. Eres en un contenedor o su kernel no soporte este opción.",
"ldap_initialized": "LDAP se inició con éxito", "ldap_initialized": "LDAP se inició con éxito",
"license_undefined": "indefinido", "license_undefined": "indefinido",
"mail_alias_remove_failed": "No se pudo quitar el alias de correos '{:s}'", "mail_alias_remove_failed": "No se pudo quitar el alias de correos '{mail:s}'",
"mail_domain_unknown": "El dominio de correos '{:s}' es desconocido", "mail_domain_unknown": "El dominio de correos '{domain:s}' es desconocido",
"mail_forward_remove_failed": "No se pudo quitar la reenvía de correos '{:s}'", "mail_forward_remove_failed": "No se pudo quitar la reenvía de correos '{mail:s}'",
"maindomain_change_failed": "No se pudo cambiar el dominio principal", "maindomain_change_failed": "No se pudo cambiar el dominio principal",
"maindomain_changed": "Dominio principal se cambió con éxito", "maindomain_changed": "Dominio principal se cambió con éxito",
"monitor_disabled": "Supervisión del sistema era desactivado con éxito", "monitor_disabled": "Supervisión del sistema era desactivado con éxito",
@ -105,7 +105,7 @@
"no_appslist_found": "No se encontró ninguna lista de Apps", "no_appslist_found": "No se encontró ninguna lista de Apps",
"no_internet_connection": "El servidor no está conectado al Internet.", "no_internet_connection": "El servidor no está conectado al Internet.",
"packages_no_upgrade": "No hay actualización por ningun paquete", "packages_no_upgrade": "No hay actualización por ningun paquete",
"packages_upgrade_critical_later": "Los paquetes críticos ({:s}) se actualizarán más tarde", "packages_upgrade_critical_later": "Los paquetes críticos ({packages:s}) se actualizarán más tarde",
"packages_upgrade_failed": "No se pudo actualizar todo de los paquetes", "packages_upgrade_failed": "No se pudo actualizar todo de los paquetes",
"path_removal_failed": "No se pudo quitar la ruta {:s}", "path_removal_failed": "No se pudo quitar la ruta {:s}",
"pattern_backup_archive_name": "Debe que ser un nombre de archivo válido con los caracteres alfanumericos, o los -_.", "pattern_backup_archive_name": "Debe que ser un nombre de archivo válido con los caracteres alfanumericos, o los -_.",
@ -118,39 +118,39 @@
"pattern_port": "El numéro del puerto debe ser válido (i.e. 0-65535)", "pattern_port": "El numéro del puerto debe ser válido (i.e. 0-65535)",
"pattern_port_or_range": "El numéro del puerto debe ser válido (i.e. 0-65535) o un intervalo de puertos (e.g. 100:200)", "pattern_port_or_range": "El numéro del puerto debe ser válido (i.e. 0-65535) o un intervalo de puertos (e.g. 100:200)",
"pattern_username": "Debe contener solamente caracteres alfanuméricos o la guion bajo", "pattern_username": "Debe contener solamente caracteres alfanuméricos o la guion bajo",
"port_already_closed": "El puerto {} ya está cerrado por {:s} connecciones.", "port_already_closed": "El puerto {port:d} ya está cerrado por {ip_version:s} connecciones",
"port_already_opened": "El puerto {} ya está abierto por {:s} connecciones", "port_already_opened": "El puerto {port:d} ya está abierto por {ip_version:s} connecciones",
"port_available": "El puerto {} está disponible", "port_available": "El puerto {port:d} está disponible",
"port_unavailable": "El puerto {} no está disponible", "port_unavailable": "El puerto {port:d} no está disponible",
"restore_complete": "Restauración se ha completado", "restore_complete": "Restauración se ha completado",
"restore_confirm_yunohost_installed": "Estás seguro que quieres restaurar a un sistema que ya está instalado? [{answers:s}]", "restore_confirm_yunohost_installed": "Estás seguro que quieres restaurar a un sistema que ya está instalado? [{answers:s}]",
"restore_failed": "No se pudo restaurar el sistema", "restore_failed": "No se pudo restaurar el sistema",
"restore_running_hooks": "Ejecutando hooks de restauración...", "restore_running_hooks": "Ejecutando hooks de restauración...",
"service_add_failed": "No se pudo añadir el servicio '{:s}'", "service_add_failed": "No se pudo añadir el servicio '{service:s}'",
"service_added": "Servicio añadido con éxito", "service_added": "Servicio añadido con éxito",
"service_already_started": "El servicio '{:s}' ya se ha empezado", "service_already_started": "El servicio '{service:s}' ya se ha empezado",
"service_already_stopped": "El servicio '{:s}' ya está parado ", "service_already_stopped": "El servicio '{service:s}' ya está parado",
"service_cmd_exec_failed": "No se pudo ejecutar comando '{:s}'", "service_cmd_exec_failed": "No se pudo ejecutar comando '{command:s}'",
"service_disable_failed": "No se pudo desactivar el servicio '{:s}'", "service_disable_failed": "No se pudo desactivar el servicio '{service:s}'",
"service_disabled": "Servicio '{:s}' desactivado con éxito", "service_disabled": "Servicio '{service:s}' desactivado con éxito",
"service_enable_failed": "No se pudo activar el servicio '{:s}'", "service_enable_failed": "No se pudo activar el servicio '{service:s}'",
"service_enabled": "Servicio '{:s}' activado con éxito", "service_enabled": "Servicio '{service:s}' activado con éxito",
"service_no_log": "No hay archivo historial del servicio '{:s}' a exhibir", "service_no_log": "No hay archivo historial del servicio '{service:s}' a exhibir",
"service_remove_failed": "No se pudo quitar el servicio '{:s}'", "service_remove_failed": "No se pudo quitar el servicio '{service:s}'",
"service_removed": "Servicio quitado con éxito", "service_removed": "Servicio quitado con éxito",
"service_start_failed": "No se pudo empezar el servicio '{:s}'", "service_start_failed": "No se pudo empezar el servicio '{service:s}'",
"service_started": "El servicio '{:s}' se empezó con éxito", "service_started": "El servicio '{service:s}' se empezó con éxito",
"service_status_failed": "No se pudo discernir el estado del servicio '{:s}'", "service_status_failed": "No se pudo discernir el estado del servicio '{service:s}'",
"service_stop_failed": "No se pudo parar el servicio '{:s}'", "service_stop_failed": "No se pudo parar el servicio '{service:s}'",
"service_stopped": "Servicio '{:s}' parado con éxito", "service_stopped": "Servicio '{service:s}' parado con éxito",
"service_unknown": "Servicio desconocido '{:s}'", "service_unknown": "Servicio desconocido '{service:s}'",
"ssowat_conf_generated": "Configuración SSOwat generado con éxito ", "ssowat_conf_generated": "Configuración SSOwat generado con éxito ",
"ssowat_conf_updated": "Configuración persistente SSOwat actualizada con éxito", "ssowat_conf_updated": "Configuración persistente SSOwat actualizada con éxito",
"system_upgraded": "Actualización del sistema se ha completado con éxito.", "system_upgraded": "Actualización del sistema se ha completado con éxito.",
"system_username_exists": "Nombre de usuario ya existe en los usuarios del sistema", "system_username_exists": "Nombre de usuario ya existe en los usuarios del sistema",
"unbackup_app": "La App '{:s}' no será guardada", "unbackup_app": "La App '{:s}' no será guardada",
"unexpected_error": "Un error ha ocurrido", "unexpected_error": "Un error ha ocurrido",
"unit_unknown": "Unidad '{:s}' desconocido", "unit_unknown": "Unidad '{unit:s}' desconocido",
"unrestore_app": "La App '{:s}' no será restaurada", "unrestore_app": "La App '{:s}' no será restaurada",
"update_cache_failed": "No se pudo actualizar el cache APT", "update_cache_failed": "No se pudo actualizar el cache APT",
"updating_apt_cache": "Actualizando la lista de paquetes disponibles...", "updating_apt_cache": "Actualizando la lista de paquetes disponibles...",

View file

@ -1,218 +1,235 @@
{ {
"action_invalid": "Action « {:s} » incorrecte", "action_invalid": "Action « {action:s} » incorrecte",
"admin_password": "Mot de passe d'administration", "admin_password": "Mot de passe d'administration",
"admin_password_change_failed": "Impossible de modifier le mot de passe d'administration", "admin_password_change_failed": "Impossible de modifier le mot de passe d'administration",
"admin_password_changed": "Mot de passe d'administration modifié avec succès", "admin_password_changed": "Mot de passe d'administration modifié avec succès",
"app_already_installed": "{app:s} est déjà installé", "app_already_installed": "{app:s} est déjà installé",
"app_argument_choice_invalid": "Choix invalide pour le paramètre « {name:s} », il doit être l'un de {choices:s}", "app_argument_choice_invalid": "Choix invalide pour le paramètre « {name:s} », il doit être l'un de {choices:s}",
"app_argument_invalid": "Valeur invalide pour le paramètre « {name:s} » : {error:s}", "app_argument_invalid": "Valeur invalide pour le paramètre « {name:s} » : {error:s}",
"app_argument_missing": "Paramètre manquant « {:s} »", "app_argument_missing": "Paramètre manquant « {:s} »",
"app_argument_required": "Le paramètre « {name:s} » est requis", "app_argument_required": "Le paramètre « {name:s} » est requis",
"app_extraction_failed": "Impossible d'extraire les fichiers d'installation", "app_extraction_failed": "Impossible d'extraire les fichiers d'installation",
"app_id_invalid": "Id d'application incorrect", "app_id_invalid": "Id d'application incorrect",
"app_install_files_invalid": "Fichiers d'installation incorrects", "app_install_files_invalid": "Fichiers d'installation incorrects",
"app_location_already_used": "Une application est déjà installée à cet emplacement", "app_location_already_used": "Une application est déjà installée à cet emplacement",
"app_location_install_failed": "Impossible d'installer l'application à cet emplacement", "app_location_install_failed": "Impossible d'installer l'application à cet emplacement",
"app_manifest_invalid": "Manifeste d'application incorrect", "app_manifest_invalid": "Manifeste d'application incorrect",
"app_no_upgrade": "Aucune application à mettre à jour", "app_no_upgrade": "Aucune application à mettre à jour",
"app_not_correctly_installed": "{app:s} semble être mal installé", "app_not_correctly_installed": "{app:s} semble être mal installé",
"app_not_installed": "{app:s} n'est pas installé", "app_not_installed": "{app:s} n'est pas installé",
"app_recent_version_required": "{app:s} nécessite une version plus récente de YunoHost", "app_not_properly_removed": "{app:s} n'a pas été supprimé correctement",
"app_removed": "{app:s} supprimé avec succès", "app_recent_version_required": "{app:s} nécessite une version plus récente de YunoHost",
"app_sources_fetch_failed": "Impossible de récupérer les fichiers sources", "app_removed": "{app:s} supprimé avec succès",
"app_unknown": "Application inconnue", "app_requirements_checking": "Vérification des paquets requis...",
"app_unsupported_remote_type": "Le type distant utilisé par l'application n'est pas supporté", "app_requirements_failed": "Impossible de satisfaire les pré-requis : {error}",
"app_upgrade_failed": "Impossible de mettre à jour {app:s}", "app_requirements_unmeet": "Les pré-requis ne sont pas satisfaits, le paquet {pkgname} ({version}) doit être {spec}",
"app_upgraded": "{app:s} mis à jour avec succès", "app_sources_fetch_failed": "Impossible de récupérer les fichiers sources",
"appslist_fetched": "Liste d'applications récupérée avec succès", "app_unknown": "Application inconnue",
"appslist_removed": "Liste d'applications supprimée avec succès", "app_unsupported_remote_type": "Le type distant utilisé par l'application n'est pas supporté",
"appslist_retrieve_error": "Impossible de récupérer la liste d'applications distante", "app_upgrade_failed": "Impossible de mettre à jour {app:s}",
"appslist_unknown": "Liste d'applications inconnue", "app_upgraded": "{app:s} mis à jour avec succès",
"ask_current_admin_password": "Mot de passe d'administration actuel", "appslist_fetched": "Liste d'applications récupérée avec succès",
"ask_email": "Adresse courriel", "appslist_removed": "Liste d'applications supprimée avec succès",
"ask_firstname": "Prénom", "appslist_retrieve_error": "Impossible de récupérer la liste d'applications distante",
"ask_lastname": "Nom", "appslist_unknown": "Liste d'applications inconnue",
"ask_list_to_remove": "Liste à supprimer", "ask_current_admin_password": "Mot de passe d'administration actuel",
"ask_main_domain": "Domaine principal", "ask_email": "Adresse courriel",
"ask_new_admin_password": "Nouveau mot de passe d'administration", "ask_firstname": "Prénom",
"ask_password": "Mot de passe", "ask_lastname": "Nom",
"backup_action_required": "Vous devez préciser ce qui est à sauvegarder", "ask_list_to_remove": "Liste à supprimer",
"backup_app_failed": "Impossible de sauvegarder l'application « {app:s} »", "ask_main_domain": "Domaine principal",
"backup_archive_app_not_found": "L'application « {app:s} » n'a pas été trouvée dans l'archive de la sauvegarde", "ask_new_admin_password": "Nouveau mot de passe d'administration",
"backup_archive_hook_not_exec": "Le script « {hook:s} » n'a pas été exécuté dans cette sauvegarde", "ask_password": "Mot de passe",
"backup_archive_name_exists": "Une archive de sauvegarde avec ce nom existe déjà", "backup_action_required": "Vous devez préciser ce qui est à sauvegarder",
"backup_archive_name_unknown": "L'archive locale de sauvegarde nommée « {name:s} » est inconnue", "backup_app_failed": "Impossible de sauvegarder l'application « {app:s} »",
"backup_archive_open_failed": "Impossible d'ouvrir l'archive de sauvegarde", "backup_archive_app_not_found": "L'application « {app:s} » n'a pas été trouvée dans l'archive de la sauvegarde",
"backup_cleaning_failed": "Impossible de nettoyer le dossier temporaire de sauvegarde", "backup_archive_hook_not_exec": "Le script « {hook:s} » n'a pas été exécuté dans cette sauvegarde",
"backup_complete": "Sauvegarde terminée", "backup_archive_name_exists": "Une archive de sauvegarde avec ce nom existe déjà",
"backup_creating_archive": "Création de l'archive de sauvegarde...", "backup_archive_name_unknown": "L'archive locale de sauvegarde nommée « {name:s} » est inconnue",
"backup_delete_error": "Impossible de supprimer « {path:s} »", "backup_archive_open_failed": "Impossible d'ouvrir l'archive de sauvegarde",
"backup_deleted": "La sauvegarde a bien été supprimée", "backup_cleaning_failed": "Impossible de nettoyer le dossier temporaire de sauvegarde",
"backup_extracting_archive": "Extraction de l'archive de sauvegarde...", "backup_complete": "Sauvegarde terminée",
"backup_hook_unknown": "Script de sauvegarde « {hook:s} » inconnu", "backup_creating_archive": "Création de l'archive de sauvegarde...",
"backup_invalid_archive": "Archive de sauvegarde incorrecte", "backup_delete_error": "Impossible de supprimer « {path:s} »",
"backup_nothings_done": "Il n'y a rien à sauvegarder", "backup_deleted": "La sauvegarde a bien été supprimée",
"backup_output_directory_forbidden": "Dossier de sortie interdit", "backup_extracting_archive": "Extraction de l'archive de sauvegarde...",
"backup_output_directory_not_empty": "Le dossier de sortie n'est pas vide", "backup_hook_unknown": "Script de sauvegarde « {hook:s} » inconnu",
"backup_output_directory_required": "Vous devez spécifier un dossier de sortie pour la sauvegarde", "backup_invalid_archive": "Archive de sauvegarde incorrecte",
"backup_running_app_script": "Lancement du script de sauvegarde de l'application « {app:s} »...", "backup_nothings_done": "Il n'y a rien à sauvegarder",
"backup_running_hooks": "Exécution des scripts de sauvegarde...", "backup_output_directory_forbidden": "Dossier de sortie interdit. Les sauvegardes ne peuvent être créées dans les dossiers /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives.",
"custom_app_url_required": "Vous devez spécifier une URL pour mettre à jour votre application locale {app:s}", "backup_output_directory_not_empty": "Le dossier de sortie n'est pas vide",
"custom_appslist_name_required": "Vous devez spécifier un nom pour votre liste d'applications personnalisée", "backup_output_directory_required": "Vous devez spécifier un dossier de sortie pour la sauvegarde",
"dnsmasq_isnt_installed": "dnsmasq ne semble pas être installé, veuillez lancer « apt-get remove bind9 && apt-get install dnsmasq »", "backup_running_app_script": "Lancement du script de sauvegarde de l'application « {app:s} »...",
"domain_cert_gen_failed": "Impossible de générer le certificat", "backup_running_hooks": "Exécution des scripts de sauvegarde...",
"domain_created": "Domaine créé avec succès", "custom_app_url_required": "Vous devez spécifier une URL pour mettre à jour votre application locale {app:s}",
"domain_creation_failed": "Impossible de créer le domaine", "custom_appslist_name_required": "Vous devez spécifier un nom pour votre liste d'applications personnalisée",
"domain_deleted": "Domaine supprimé avec succès", "diagnostic_debian_version_error": "Impossible de déterminer la version de Debian : {error}",
"domain_deletion_failed": "Impossible de supprimer le domaine", "diagnostic_kernel_version_error": "Impossible de récupérer la version du noyau : {error}",
"domain_dyndns_already_subscribed": "Vous avez déjà souscris à un domaine DynDNS", "diagnostic_monitor_disk_error": "Impossible de superviser les disques : {error}",
"domain_dyndns_invalid": "Domaine incorrect pour un usage avec DynDNS", "diagnostic_monitor_network_error": "Impossible de superviser le réseau : {error}",
"domain_dyndns_root_unknown": "Domaine DynDNS principal inconnu", "diagnostic_monitor_system_error": "Impossible de superviser le système : {error}",
"domain_exists": "Le domaine existe déjà", "diagnostic_no_apps": "Aucune application installée",
"domain_uninstall_app_first": "Une ou plusieurs applications sont installées sur ce domaine. Veuillez d'abord les désinstaller avant de supprimer ce domaine.", "dnsmasq_isnt_installed": "dnsmasq ne semble pas être installé, veuillez lancer « apt-get remove bind9 && apt-get install dnsmasq »",
"domain_unknown": "Domaine inconnu", "domain_cert_gen_failed": "Impossible de générer le certificat",
"domain_zone_exists": "Le fichier de zone DNS existe déjà", "domain_created": "Domaine créé avec succès",
"domain_zone_not_found": "Fichier de zone DNS introuvable pour le domaine {:s}", "domain_creation_failed": "Impossible de créer le domaine",
"done": "Terminé.", "domain_deleted": "Domaine supprimé avec succès",
"downloading": "Téléchargement...", "domain_deletion_failed": "Impossible de supprimer le domaine",
"dyndns_cron_installed": "Tâche cron pour DynDNS installée avec succès", "domain_dyndns_already_subscribed": "Vous avez déjà souscris à un domaine DynDNS",
"dyndns_cron_remove_failed": "Impossible d'enlever la tâche cron pour DynDNS", "domain_dyndns_invalid": "Domaine incorrect pour un usage avec DynDNS",
"dyndns_cron_removed": "La tâche cron pour DynDNS a été enlevée avec succès", "domain_dyndns_root_unknown": "Domaine DynDNS principal inconnu",
"dyndns_ip_update_failed": "Impossible de mettre à jour l'adresse IP sur le domaine DynDNS", "domain_exists": "Le domaine existe déjà",
"dyndns_ip_updated": "Adresse IP mise à jour avec succès sur le domaine DynDNS", "domain_uninstall_app_first": "Une ou plusieurs applications sont installées sur ce domaine. Veuillez d'abord les désinstaller avant de supprimer ce domaine.",
"dyndns_key_generating": "La clé DNS est en cours de génération, cela peut prendre du temps...", "domain_unknown": "Domaine inconnu",
"dyndns_registered": "Domaine DynDNS enregistré avec succès", "domain_zone_exists": "Le fichier de zone DNS existe déjà",
"dyndns_registration_failed": "Impossible d'enregistrer le domaine DynDNS : {:s}", "domain_zone_not_found": "Fichier de zone DNS introuvable pour le domaine {:s}",
"dyndns_unavailable": "Sous-domaine DynDNS indisponible", "done": "Terminé.",
"executing_command": "Exécution de la commande « {command:s} »...", "downloading": "Téléchargement...",
"executing_script": "Exécution du script « {script:s} »...", "dyndns_cron_installed": "Tâche cron pour DynDNS installée avec succès",
"extracting": "Extraction...", "dyndns_cron_remove_failed": "Impossible d'enlever la tâche cron pour DynDNS",
"field_invalid": "Champ incorrect : « {:s} »", "dyndns_cron_removed": "La tâche cron pour DynDNS a été enlevée avec succès",
"firewall_reload_failed": "Impossible de recharger le pare-feu", "dyndns_ip_update_failed": "Impossible de mettre à jour l'adresse IP sur le domaine DynDNS",
"firewall_reloaded": "Pare-feu rechargé avec succès", "dyndns_ip_updated": "Adresse IP mise à jour avec succès sur le domaine DynDNS",
"firewall_rules_cmd_failed": "Certaines règles du pare-feu n'ont pas pu être appliquées. Pour plus d'informations, consultez le journal.", "dyndns_key_generating": "La clé DNS est en cours de génération, cela peut prendre du temps...",
"format_datetime_short": "%d/%m/%Y %H:%M", "dyndns_key_not_found": "Clé DNS introuvable pour le domaine",
"hook_argument_missing": "Argument manquant : '{:s}'", "dyndns_no_domain_registered": "Aucun domaine n'a été enregistré avec DynDNS",
"hook_choice_invalid": "Choix incorrect : '{:s}'", "dyndns_registered": "Domaine DynDNS enregistré avec succès",
"hook_exec_failed": "Échec de l'exécution du script", "dyndns_registration_failed": "Impossible d'enregistrer le domaine DynDNS : {error:s}",
"hook_exec_not_terminated": "L'exécution du script ne s'est pas terminée", "dyndns_unavailable": "Sous-domaine DynDNS indisponible",
"hook_list_by_invalid": "Propriété pour lister les scripts incorrecte", "executing_command": "Exécution de la commande « {command:s} »...",
"hook_name_unknown": "Nom de script « {:s} » inconnu", "executing_script": "Exécution du script « {script:s} »...",
"installation_complete": "Installation terminée", "extracting": "Extraction...",
"installation_failed": "Échec de l'installation", "field_invalid": "Champ incorrect : « {:s} »",
"ip6tables_unavailable": "Vous ne pouvez pas jouer avec ip6tables ici. Vous êtes sûrement dans un conteneur, ou alors votre noyau ne le supporte pas.", "firewall_reload_failed": "Impossible de recharger le pare-feu",
"iptables_unavailable": "Vous ne pouvez pas jouer avec iptables ici. Vous êtes sûrement dans un conteneur, autrement votre noyau ne le supporte pas.", "firewall_reloaded": "Pare-feu rechargé avec succès",
"ldap_initialized": "Répertoire LDAP initialisé avec succès", "firewall_rules_cmd_failed": "Certaines règles du pare-feu n'ont pas pu être appliquées. Pour plus d'informations, consultez le journal.",
"license_undefined": "indéfinie", "format_datetime_short": "%d/%m/%Y %H:%M",
"mail_alias_remove_failed": "Impossible de supprimer l'adresse mail supplémentaire « {:s} »", "hook_argument_missing": "Argument manquant : '{:s}'",
"mail_domain_unknown": "Domaine « {:s} » de l'adresse mail inconnu", "hook_choice_invalid": "Choix incorrect : '{:s}'",
"mail_forward_remove_failed": "Impossible de supprimer l'adresse courriel de transfert « {:s} »", "hook_exec_failed": "Échec de l'exécution du script « {path:s} »",
"maindomain_change_failed": "Impossible de modifier le domaine principal", "hook_exec_not_terminated": "L'exécution du script « {path:s} » ne s'est pas terminée",
"maindomain_changed": "Domaine principal modifié avec succès", "hook_list_by_invalid": "Propriété pour lister les scripts incorrecte",
"monitor_disabled": "Le suivi de l'état du serveur a été désactivé avec succès", "hook_name_unknown": "Nom de script « {name:s} » inconnu",
"monitor_enabled": "Suivi de l'état du serveur activé avec succès", "installation_complete": "Installation terminée",
"monitor_glances_con_failed": "Impossible de se connecter au serveur Glances", "installation_failed": "Échec de l'installation",
"monitor_not_enabled": "Le suivi de l'état du serveur n'est pas activé", "ip6tables_unavailable": "Vous ne pouvez pas jouer avec ip6tables ici. Vous êtes sûrement dans un conteneur, ou alors votre noyau ne le supporte pas.",
"monitor_period_invalid": "Période de temps incorrecte", "iptables_unavailable": "Vous ne pouvez pas jouer avec iptables ici. Vous êtes sûrement dans un conteneur, autrement votre noyau ne le supporte pas.",
"monitor_stats_file_not_found": "Le fichier de statistiques est introuvable", "ldap_initialized": "Répertoire LDAP initialisé avec succès",
"monitor_stats_no_update": "Aucune donnée de l'état du serveur à mettre à jour", "license_undefined": "indéfinie",
"monitor_stats_period_unavailable": "Aucune statistique n'est disponible pour la période", "mail_alias_remove_failed": "Impossible de supprimer l'adresse mail supplémentaire « {mail:s} »",
"mountpoint_unknown": "Point de montage inconnu", "mail_domain_unknown": "Domaine « {domain:s} » de l'adresse mail inconnu",
"mysql_db_creation_failed": "Impossible de créer la base de données MySQL", "mail_forward_remove_failed": "Impossible de supprimer l'adresse courriel de transfert « {mail:s} »",
"mysql_db_init_failed": "Impossible d'initialiser la base de données MySQL", "maindomain_change_failed": "Impossible de modifier le domaine principal",
"mysql_db_initialized": "Base de donnée MySQL initialisée avec succès", "maindomain_changed": "Domaine principal modifié avec succès",
"network_check_mx_ko": "L'enregistrement DNS MX n'est pas précisé", "monitor_disabled": "Le suivi de l'état du serveur a été désactivé avec succès",
"network_check_smtp_ko": "Le trafic mail sortant (port 25 SMTP) semble bloqué par votre réseau", "monitor_enabled": "Suivi de l'état du serveur activé avec succès",
"network_check_smtp_ok": "Le trafic courriel sortant (port 25 SMTP) n'est pas bloqué", "monitor_glances_con_failed": "Impossible de se connecter au serveur Glances",
"new_domain_required": "Vous devez spécifier le nouveau domaine principal", "monitor_not_enabled": "Le suivi de l'état du serveur n'est pas activé",
"no_appslist_found": "Aucune liste d'applications trouvée", "monitor_period_invalid": "Période de temps incorrecte",
"no_internet_connection": "Le serveur n'est pas connecté à internet", "monitor_stats_file_not_found": "Le fichier de statistiques est introuvable",
"no_ipv6_connectivity": "La connectivité IPv6 n'est pas disponible", "monitor_stats_no_update": "Aucune donnée de l'état du serveur à mettre à jour",
"no_restore_script": "Le script de sauvegarde n'a pas été trouvé pour l'application « {app:s} »", "monitor_stats_period_unavailable": "Aucune statistique n'est disponible pour la période",
"no_such_conf_file": "Le fichier {file:s} nexiste pas, il ne peut pas être copié", "mountpoint_unknown": "Point de montage inconnu",
"not_enough_disk_space": "L'espace disque est insuffisant sur « {path:s} »", "mysql_db_creation_failed": "Impossible de créer la base de données MySQL",
"packages_no_upgrade": "Il n'y a aucun paquet à mettre à jour", "mysql_db_init_failed": "Impossible d'initialiser la base de données MySQL",
"packages_upgrade_critical_later": "Les paquets critiques ({:s}) seront mis à jour ultérieurement", "mysql_db_initialized": "Base de donnée MySQL initialisée avec succès",
"packages_upgrade_failed": "Impossible de mettre à jour tous les paquets", "network_check_mx_ko": "L'enregistrement DNS MX n'est pas précisé",
"path_removal_failed": "Impossible de supprimer le chemin {:s}", "network_check_smtp_ko": "Le trafic mail sortant (port 25 SMTP) semble bloqué par votre réseau",
"pattern_backup_archive_name": "Doit être un nom de fichier valide composé de caractères alphanumérique et -_. uniquement", "network_check_smtp_ok": "Le trafic courriel sortant (port 25 SMTP) n'est pas bloqué",
"pattern_domain": "Doit être un nom de domaine valide (ex : mon-domaine.org)", "new_domain_required": "Vous devez spécifier le nouveau domaine principal",
"pattern_email": "Doit être une adresse courriel valide (ex. : someone@domain.org)", "no_appslist_found": "Aucune liste d'applications trouvée",
"pattern_firstname": "Doit être un prénom valide", "no_internet_connection": "Le serveur n'est pas connecté à internet",
"pattern_lastname": "Doit être un nom valide", "no_ipv6_connectivity": "La connectivité IPv6 n'est pas disponible",
"pattern_listname": "Doit être composé uniquement de caractères alphanumériques et de tirets bas", "no_restore_script": "Le script de sauvegarde n'a pas été trouvé pour l'application « {app:s} »",
"pattern_mailbox_quota": "Doit être une taille avec le suffixe b/k/M/G/T ou 0 pour désactiver le quota", "no_such_conf_file": "Le fichier {file:s} nexiste pas, il ne peut pas être copié",
"pattern_password": "Doit être composé d'au moins 3 caractères", "not_enough_disk_space": "L'espace disque est insuffisant sur « {path:s} »",
"pattern_port": "Doit être un numéro de port valide (ex. : 0-65535)", "package_not_installed": "Le paquet « {pkgname} » n'est pas installé",
"pattern_port_or_range": "Doit être un numéro de port valide (ex. : 0-65535) ou une gamme de ports (ex. : 100:200)", "package_unexpected_error": "Une erreur inattendue est survenue avec le paquet « {pkgname} »",
"pattern_positive_number": "Doit être un nombre positif", "package_unknown": "Paquet « {pkgname} » inconnu",
"pattern_username": "Doit être composé uniquement de caractères alphanumériques minuscules et de tirets bas", "packages_no_upgrade": "Il n'y a aucun paquet à mettre à jour",
"port_already_closed": "Le port {} est déjà fermé pour les connexions {:s}", "packages_upgrade_critical_later": "Les paquets critiques ({packages:s}) seront mis à jour ultérieurement",
"port_already_opened": "Le port {} est déjà ouvert pour les connexions {:s}", "packages_upgrade_failed": "Impossible de mettre à jour tous les paquets",
"port_available": "Le port {port:d} est disponible", "path_removal_failed": "Impossible de supprimer le chemin {:s}",
"port_unavailable": "Le port {port:d} n'est pas disponible", "pattern_backup_archive_name": "Doit être un nom de fichier valide composé de caractères alphanumérique et -_. uniquement",
"restore_action_required": "Vous devez préciser ce qui est à restaurer", "pattern_domain": "Doit être un nom de domaine valide (ex : mon-domaine.org)",
"restore_already_installed_app": "Une application est déjà installée avec l'id « {app:s} »", "pattern_email": "Doit être une adresse courriel valide (ex. : someone@domain.org)",
"restore_app_failed": "Impossible de restaurer l'application « {app:s} »", "pattern_firstname": "Doit être un prénom valide",
"restore_cleaning_failed": "Impossible de nettoyer le dossier temporaire de restauration", "pattern_lastname": "Doit être un nom valide",
"restore_complete": "Restauration terminée", "pattern_listname": "Doit être composé uniquement de caractères alphanumériques et de tirets bas",
"restore_confirm_yunohost_installed": "Voulez-vous vraiment restaurer un système déjà installé ? [{answers:s}]", "pattern_mailbox_quota": "Doit être une taille avec le suffixe b/k/M/G/T ou 0 pour désactiver le quota",
"restore_failed": "Impossible de restaurer le système", "pattern_password": "Doit être composé d'au moins 3 caractères",
"restore_hook_unavailable": "Le script de restauration « {hook:s} » n'est pas disponible sur votre système", "pattern_port": "Doit être un numéro de port valide (ex. : 0-65535)",
"restore_nothings_done": "Rien n'a été restauré", "pattern_port_or_range": "Doit être un numéro de port valide (ex. : 0-65535) ou une gamme de ports (ex. : 100:200)",
"restore_running_app_script": "Lancement du script de restauration pour l'application « {app:s} »...", "pattern_positive_number": "Doit être un nombre positif",
"restore_running_hooks": "Exécution des scripts de restauration...", "pattern_username": "Doit être composé uniquement de caractères alphanumériques minuscules et de tirets bas",
"service_add_configuration": "Ajout du fichier de configuration {file:s}", "port_already_closed": "Le port {port:d} est déjà fermé pour les connexions {ip_version:s}",
"service_add_failed": "Impossible d'ajouter le service « {:s} »", "port_already_opened": "Le port {port:d} est déjà ouvert pour les connexions {ip_version:s}",
"service_added": "Service ajouté avec succès", "port_available": "Le port {port:d} est disponible",
"service_already_started": "Le service « {:s} » est déjà démarré", "port_unavailable": "Le port {port:d} n'est pas disponible",
"service_already_stopped": "Le service « {:s} » est déjà arrêté", "restore_action_required": "Vous devez préciser ce qui est à restaurer",
"service_cmd_exec_failed": "Impossible d'exécuter la commande « {:s} »", "restore_already_installed_app": "Une application est déjà installée avec l'id « {app:s} »",
"service_configuration_conflict": "Le fichier {file:s} a été modifié depuis sa dernière génération. Veuillez y appliquer les modifications manuellement ou utiliser loption --force (ce qui écrasera toutes les modifications effectuées sur le fichier).", "restore_app_failed": "Impossible de restaurer l'application « {app:s} »",
"service_disable_failed": "Impossible de désactiver le service « {:s} »", "restore_cleaning_failed": "Impossible de nettoyer le dossier temporaire de restauration",
"service_disabled": "Service « {:s} » désactivé avec succès", "restore_complete": "Restauration terminée",
"service_enable_failed": "Impossible d'activer le service « {:s} »", "restore_confirm_yunohost_installed": "Voulez-vous vraiment restaurer un système déjà installé ? [{answers:s}]",
"service_enabled": "Service « {:s} » activé avec succès", "restore_failed": "Impossible de restaurer le système",
"service_no_log": "Aucun journal à afficher pour le service « {:s} »", "restore_hook_unavailable": "Le script de restauration « {hook:s} » n'est pas disponible sur votre système",
"service_remove_failed": "Impossible d'enlever le service « {:s} »", "restore_nothings_done": "Rien n'a été restauré",
"service_removed": "Service enlevé avec succès", "restore_running_app_script": "Lancement du script de restauration pour l'application « {app:s} »...",
"service_start_failed": "Impossible de démarrer le service « {:s} »", "restore_running_hooks": "Exécution des scripts de restauration...",
"service_started": "Le service « {:s} » a démarré avec succès", "service_add_configuration": "Ajout du fichier de configuration {file:s}",
"service_status_failed": "Impossible de déterminer le statut du service « {:s} »", "service_add_failed": "Impossible d'ajouter le service « {service:s} »",
"service_stop_failed": "Impossible d'arrêter le service « {:s} »", "service_added": "Service « {service:s} » ajouté avec succès",
"service_stopped": "Service « {:s} » arrêté avec succès", "service_already_started": "Le service « {service:s} » est déjà démarré",
"service_unknown": "Service « {:s} » inconnu", "service_already_stopped": "Le service « {service:s} » est déjà arrêté",
"services_configured": "La configuration a été générée avec succès", "service_cmd_exec_failed": "Impossible d'exécuter la commande « {command:s} »",
"show_diff": "Voici les différences :\n{diff:s}", "service_configuration_conflict": "Le fichier {file:s} a été modifié depuis sa dernière génération. Veuillez y appliquer les modifications manuellement ou utiliser loption --force (ce qui écrasera toutes les modifications effectuées sur le fichier).",
"ssowat_conf_generated": "Configuration de SSOwat générée avec succès", "service_configured": "La configuration du service « {service:s} » a été générée avec succès",
"ssowat_conf_updated": "La configuration persistante de SSOwat a été mise à jour avec succès", "service_configured_all": "La configuration de tous les services a été générée avec succès",
"system_upgraded": "Système mis à jour avec succès", "service_disable_failed": "Impossible de désactiver le service « {service:s} »",
"system_username_exists": "Le nom d'utilisateur existe déjà dans les utilisateurs système", "service_disabled": "Service « {service:s} » désactivé avec succès",
"unbackup_app": "L'application « {app:s} » ne sera pas sauvegardée", "service_enable_failed": "Impossible d'activer le service « {service:s} »",
"unexpected_error": "Une erreur inattendue est survenue", "service_enabled": "Service « {service:s} » activé avec succès",
"unit_unknown": "Unité « {:s} » inconnue", "service_no_log": "Aucun journal à afficher pour le service « {service:s} »",
"unlimit": "Pas de quota", "service_remove_failed": "Impossible d'enlever le service « {service:s} »",
"unrestore_app": "L'application « {app:s} » ne sera pas restaurée", "service_removed": "Service « {service:s} » enlevé avec succès",
"update_cache_failed": "Impossible de mettre à jour le cache de l'APT", "service_start_failed": "Impossible de démarrer le service « {service:s} »",
"updating_apt_cache": "Mise à jour de la liste des paquets disponibles...", "service_started": "Le service « {service:s} » a démarré avec succès",
"upgrade_complete": "Mise à jour terminée", "service_status_failed": "Impossible de déterminer le statut du service « {service:s} »",
"upgrading_packages": "Mise à jour des paquets...", "service_stop_failed": "Impossible d'arrêter le service « {service:s} »",
"upnp_dev_not_found": "Aucun périphérique compatible UPnP n'a été trouvé", "service_stopped": "Service « {service:s} » arrêté avec succès",
"upnp_disabled": "UPnP désactivé avec succès", "service_unknown": "Service « {service:s} » inconnu",
"upnp_enabled": "UPnP activé avec succès", "services_configured": "La configuration a été générée avec succès",
"upnp_port_open_failed": "Impossible d'ouvrir les ports avec UPnP", "show_diff": "Voici les différences :\n{diff:s}",
"user_created": "Utilisateur créé avec succès", "ssowat_conf_generated": "Configuration de SSOwat générée avec succès",
"user_creation_failed": "Impossible de créer l'utilisateur", "ssowat_conf_updated": "La configuration persistante de SSOwat a été mise à jour avec succès",
"user_deleted": "Utilisateur supprimé avec succès", "system_upgraded": "Système mis à jour avec succès",
"user_deletion_failed": "Impossible de supprimer l'utilisateur", "system_username_exists": "Le nom d'utilisateur existe déjà dans les utilisateurs système",
"user_home_creation_failed": "Impossible de créer le dossier personnel de l'utilisateur", "unbackup_app": "L'application « {app:s} » ne sera pas sauvegardée",
"user_info_failed": "Impossible de récupérer les informations de l'utilisateur", "unexpected_error": "Une erreur inattendue est survenue",
"user_unknown": "Utilisateur inconnu", "unit_unknown": "Unité « {unit:s} » inconnue",
"user_update_failed": "Impossible de modifier l'utilisateur", "unlimit": "Pas de quota",
"user_updated": "Utilisateur modifié avec succès", "unrestore_app": "L'application « {app:s} » ne sera pas restaurée",
"yunohost_already_installed": "YunoHost est déjà installé", "update_cache_failed": "Impossible de mettre à jour le cache de l'APT",
"yunohost_ca_creation_failed": "Impossible de créer l'autorité de certification", "updating_apt_cache": "Mise à jour de la liste des paquets disponibles...",
"yunohost_configured": "YunoHost configuré avec succès", "upgrade_complete": "Mise à jour terminée",
"yunohost_installing": "Installation de YunoHost...", "upgrading_packages": "Mise à jour des paquets...",
"upnp_dev_not_found": "Aucun périphérique compatible UPnP n'a été trouvé",
"upnp_disabled": "UPnP désactivé avec succès",
"upnp_enabled": "UPnP activé avec succès",
"upnp_port_open_failed": "Impossible d'ouvrir les ports avec UPnP",
"user_created": "Utilisateur créé avec succès",
"user_creation_failed": "Impossible de créer l'utilisateur",
"user_deleted": "Utilisateur supprimé avec succès",
"user_deletion_failed": "Impossible de supprimer l'utilisateur",
"user_home_creation_failed": "Impossible de créer le dossier personnel de l'utilisateur",
"user_info_failed": "Impossible de récupérer les informations de l'utilisateur",
"user_unknown": "Utilisateur « {user:s} » inconnu",
"user_update_failed": "Impossible de modifier l'utilisateur",
"user_updated": "Utilisateur modifié avec succès",
"yunohost_already_installed": "YunoHost est déjà installé",
"yunohost_ca_creation_failed": "Impossible de créer l'autorité de certification",
"yunohost_configured": "YunoHost configuré avec succès",
"yunohost_installing": "Installation de YunoHost...",
"yunohost_not_installed": "YunoHost n'est pas ou pas correctement installé. Veuillez exécuter « yunohost tools postinstall »." "yunohost_not_installed": "YunoHost n'est pas ou pas correctement installé. Veuillez exécuter « yunohost tools postinstall »."
} }

View file

@ -1,31 +1,31 @@
{ {
"app_already_installed": "{:s} è già installato", "app_already_installed": "{app:s} è già installato",
"app_extraction_failed": "Impossibile estrarre i file di installazione", "app_extraction_failed": "Impossibile estrarre i file di installazione",
"app_not_installed": "{:s} non è installato", "app_not_installed": "{app:s} non è installato",
"app_unknown": "Applicazione sconosciuta", "app_unknown": "Applicazione sconosciuta",
"ask_email": "Indirizzo email", "ask_email": "Indirizzo email",
"ask_password": "Password", "ask_password": "Password",
"backup_archive_name_exists": "Il nome dell'archivio del backup esiste già", "backup_archive_name_exists": "Il nome dell'archivio del backup esiste già",
"backup_complete": "Backup completo", "backup_complete": "Backup completo",
"backup_invalid_archive": "Archivio di backup non valido", "backup_invalid_archive": "Archivio di backup non valido",
"backup_output_directory_not_empty": "Directory di output non è vuota", "backup_output_directory_not_empty": "Directory di output non è vuota",
"backup_running_app_script": "Esecuzione script di backup dell'applicazione '{:s}'...", "backup_running_app_script": "Esecuzione script di backup dell'applicazione '{app:s}'...",
"domain_created": "Dominio creato con successo", "domain_created": "Dominio creato con successo",
"domain_dyndns_invalid": "Dominio non valido da utilizzare con DynDNS", "domain_dyndns_invalid": "Dominio non valido da utilizzare con DynDNS",
"domain_exists": "Dominio esiste già", "domain_exists": "Dominio esiste già",
"ldap_initialized": "LDAP inizializzato con successo", "ldap_initialized": "LDAP inizializzato con successo",
"pattern_email": "Deve essere un indirizzo e-mail valido (es someone@domain.org)", "pattern_email": "Deve essere un indirizzo e-mail valido (es someone@domain.org)",
"pattern_mailbox_quota": "Deve essere una dimensione con un suffisso b/k/M/G/T o 0 per disabilitare la quota", "pattern_mailbox_quota": "Deve essere una dimensione con un suffisso b/k/M/G/T o 0 per disabilitare la quota",
"port_already_opened": "Port {} è già aperto per {:s} connessioni", "port_already_opened": "Port {port:d} è già aperto per {ip_version:s} connessioni",
"port_unavailable": "Porta {} non è disponibile", "port_unavailable": "Porta {port:d} non è disponibile",
"service_add_failed": "Impossibile aggiungere servizio '{:s}'", "service_add_failed": "Impossibile aggiungere servizio '{service:s}'",
"service_cmd_exec_failed": "Impossibile eseguire il comando '{:s}'", "service_cmd_exec_failed": "Impossibile eseguire il comando '{command:s}'",
"service_disabled": "Servizio '{:s}' disattivato con successo", "service_disabled": "Servizio '{service:s}' disattivato con successo",
"service_remove_failed": "Impossibile rimuovere il servizio '{:s}'", "service_remove_failed": "Impossibile rimuovere il servizio '{service:s}'",
"service_removed": "Servizio rimosso con successo", "service_removed": "Servizio rimosso con successo",
"service_stop_failed": "Impossibile arrestare il servizio '{:s}'", "service_stop_failed": "Impossibile arrestare il servizio '{service:s}'",
"system_username_exists": "Nome utente esiste già negli utenti del sistema", "system_username_exists": "Nome utente esiste già negli utenti del sistema",
"unrestore_app": "Applicazione '{app:s}' non verrà ripristinato", "unrestore_app": "Applicazione '{app:s}' non verrà ripristinato",
"upgrading_packages": "Aggiornamento dei pacchetti...", "upgrading_packages": "Aggiornamento dei pacchetti...",
"user_deleted": "Utente cancellato con successo" "user_deleted": "Utente cancellato con successo"
} }

View file

@ -1,109 +1,109 @@
{ {
"action_invalid": "Ongeldige actie '{:s}'", "action_invalid": "Ongeldige actie '{action:s}'",
"admin_password": "Administration password", "admin_password": "Administration password",
"admin_password_changed": "Het admin-wachtwoord is gewijzigd", "admin_password_changed": "Het admin-wachtwoord is gewijzigd",
"app_already_installed": "{:s} is al geïnstalleerd", "app_already_installed": "{app:s} is al geïnstalleerd",
"app_argument_invalid": "'{name:s}' bevat geldige waarde: {error:s}", "app_argument_invalid": "'{name:s}' bevat geldige waarde: {error:s}",
"app_argument_required": "Het '{name:s}' moet ingevuld worden", "app_argument_required": "Het '{name:s}' moet ingevuld worden",
"app_extraction_failed": "Kan installatiebestanden niet uitpakken", "app_extraction_failed": "Kan installatiebestanden niet uitpakken",
"app_id_invalid": "Ongeldige app-id", "app_id_invalid": "Ongeldige app-id",
"app_install_files_invalid": "Ongeldige installatiebestanden", "app_install_files_invalid": "Ongeldige installatiebestanden",
"app_location_already_used": "Er is al een app geïnstalleerd op deze locatie", "app_location_already_used": "Er is al een app geïnstalleerd op deze locatie",
"app_location_install_failed": "Kan app niet installeren op deze locatie", "app_location_install_failed": "Kan app niet installeren op deze locatie",
"app_manifest_invalid": "Ongeldig app-manifest", "app_manifest_invalid": "Ongeldig app-manifest",
"app_no_upgrade": "Geen apps op te upgraden", "app_no_upgrade": "Geen apps op te upgraden",
"app_not_installed": "{:s} is niet geinstalleerd ", "app_not_installed": "{app:s} is niet geinstalleerd",
"app_recent_version_required": "{:s} vereist een nieuwere versie van moulinette", "app_recent_version_required": "{:s} vereist een nieuwere versie van moulinette",
"app_removed": "{:s} succesvol verwijderd", "app_removed": "{app:s} succesvol verwijderd",
"app_sources_fetch_failed": "Kan bronbestanden niet ophalen", "app_sources_fetch_failed": "Kan bronbestanden niet ophalen",
"app_unknown": "Onbekende app", "app_unknown": "Onbekende app",
"app_upgrade_failed": "Kan niet alle apps updaten", "app_upgrade_failed": "Kan niet alle apps updaten",
"app_upgraded": "{:s} succesvol geüpgrade ", "app_upgraded": "{app:s} succesvol geüpgrade",
"appslist_fetched": "App-lijst succesvol aangemaakt.", "appslist_fetched": "App-lijst succesvol aangemaakt.",
"appslist_removed": "App-lijst succesvol verwijderd", "appslist_removed": "App-lijst succesvol verwijderd",
"appslist_unknown": "Onbekende app-lijst", "appslist_unknown": "Onbekende app-lijst",
"ask_current_admin_password": "Huidig administratorwachtwoord", "ask_current_admin_password": "Huidig administratorwachtwoord",
"ask_email": "Email-adres", "ask_email": "Email-adres",
"ask_firstname": "Voornaam", "ask_firstname": "Voornaam",
"ask_lastname": "Achternaam", "ask_lastname": "Achternaam",
"ask_new_admin_password": "Nieuw administratorwachtwoord", "ask_new_admin_password": "Nieuw administratorwachtwoord",
"ask_password": "Wachtwoord", "ask_password": "Wachtwoord",
"backup_archive_name_exists": "Backuparchief bestaat al", "backup_archive_name_exists": "Backuparchief bestaat al",
"backup_cleaning_failed": "Kan tijdelijke backup directory niet leeg maken", "backup_cleaning_failed": "Kan tijdelijke backup directory niet leeg maken",
"backup_creating_archive": "Backup wordt gestart...", "backup_creating_archive": "Backup wordt gestart...",
"backup_invalid_archive": "Ongeldig backup archief", "backup_invalid_archive": "Ongeldig backup archief",
"backup_output_directory_not_empty": "Doelmap is niet leeg", "backup_output_directory_not_empty": "Doelmap is niet leeg",
"backup_running_app_script": "Backup script voor app '{app:s}' is gestart...", "backup_running_app_script": "Backup script voor app '{app:s}' is gestart...",
"custom_app_url_required": "U moet een URL opgeven om uw aangepaste app {:s} bij te werken", "custom_app_url_required": "U moet een URL opgeven om uw aangepaste app {app:s} bij te werken",
"custom_appslist_name_required": "U moet een naam opgeven voor uw aangepaste app-lijst", "custom_appslist_name_required": "U moet een naam opgeven voor uw aangepaste app-lijst",
"dnsmasq_isnt_installed": "dnsmasq lijkt niet geïnstalleerd te zijn, voer alstublieft het volgende commando uit: 'apt-get remove bind9 && apt-get install dnsmasq'", "dnsmasq_isnt_installed": "dnsmasq lijkt niet geïnstalleerd te zijn, voer alstublieft het volgende commando uit: 'apt-get remove bind9 && apt-get install dnsmasq'",
"domain_cert_gen_failed": "Kan certificaat niet genereren", "domain_cert_gen_failed": "Kan certificaat niet genereren",
"domain_created": "Domein succesvol aangemaakt", "domain_created": "Domein succesvol aangemaakt",
"domain_creation_failed": "Kan domein niet aanmaken", "domain_creation_failed": "Kan domein niet aanmaken",
"domain_deleted": "Domein succesvol verwijderd", "domain_deleted": "Domein succesvol verwijderd",
"domain_deletion_failed": "Kan domein niet verwijderen", "domain_deletion_failed": "Kan domein niet verwijderen",
"domain_dyndns_already_subscribed": "Dit domein is al geregistreed bij DynDNS", "domain_dyndns_already_subscribed": "Dit domein is al geregistreed bij DynDNS",
"domain_dyndns_invalid": "Het domein is ongeldig voor DynDNS", "domain_dyndns_invalid": "Het domein is ongeldig voor DynDNS",
"domain_dyndns_root_unknown": "Onbekend DynDNS root domein", "domain_dyndns_root_unknown": "Onbekend DynDNS root domein",
"domain_exists": "Domein bestaat al", "domain_exists": "Domein bestaat al",
"domain_uninstall_app_first": "Een of meerdere apps zijn geïnstalleerd op dit domein, verwijder deze voordat u het domein verwijderd.", "domain_uninstall_app_first": "Een of meerdere apps zijn geïnstalleerd op dit domein, verwijder deze voordat u het domein verwijderd.",
"domain_unknown": "Onbekend domein", "domain_unknown": "Onbekend domein",
"domain_zone_exists": "DNS zone bestand bestaat al", "domain_zone_exists": "DNS zone bestand bestaat al",
"domain_zone_not_found": "DNS zone bestand niet gevonden voor domein: {:s}", "domain_zone_not_found": "DNS zone bestand niet gevonden voor domein: {:s}",
"done": "Voltooid.", "done": "Voltooid.",
"downloading": "Downloaden...", "downloading": "Downloaden...",
"dyndns_cron_remove_failed": "De cron-job voor DynDNS kon niet worden verwijderd", "dyndns_cron_remove_failed": "De cron-job voor DynDNS kon niet worden verwijderd",
"dyndns_ip_update_failed": "Kan het IP adres niet updaten bij DynDNS", "dyndns_ip_update_failed": "Kan het IP adres niet updaten bij DynDNS",
"dyndns_ip_updated": "IP adres is aangepast bij DynDNS", "dyndns_ip_updated": "IP adres is aangepast bij DynDNS",
"dyndns_key_generating": "DNS sleutel word aangemaakt, wacht een moment...", "dyndns_key_generating": "DNS sleutel word aangemaakt, wacht een moment...",
"dyndns_unavailable": "DynDNS subdomein is niet beschikbaar", "dyndns_unavailable": "DynDNS subdomein is niet beschikbaar",
"executing_script": "Script uitvoeren...", "executing_script": "Script uitvoeren...",
"extracting": "Uitpakken...", "extracting": "Uitpakken...",
"installation_complete": "Installatie voltooid", "installation_complete": "Installatie voltooid",
"installation_failed": "Installatie gefaald", "installation_failed": "Installatie gefaald",
"ldap_initialized": "LDAP staat klaar voor gebruik", "ldap_initialized": "LDAP staat klaar voor gebruik",
"license_undefined": "undefined", "license_undefined": "undefined",
"mail_alias_remove_failed": "Kan mail alias niet verwijderen '{:s}'", "mail_alias_remove_failed": "Kan mail alias niet verwijderen '{mail:s}'",
"monitor_stats_no_update": "Er zijn geen recente monitoringstatistieken bij te werken", "monitor_stats_no_update": "Er zijn geen recente monitoringstatistieken bij te werken",
"mysql_db_creation_failed": "Aanmaken MySQL database gefaald", "mysql_db_creation_failed": "Aanmaken MySQL database gefaald",
"mysql_db_init_failed": "Initialiseren MySQL database gefaald", "mysql_db_init_failed": "Initialiseren MySQL database gefaald",
"mysql_db_initialized": "MySQL database succesvol geïnitialiseerd", "mysql_db_initialized": "MySQL database succesvol geïnitialiseerd",
"network_check_smtp_ko": "Uitgaande mail (SMPT port 25) wordt blijkbaar geblokkeerd door uw het netwerk", "network_check_smtp_ko": "Uitgaande mail (SMPT port 25) wordt blijkbaar geblokkeerd door uw het netwerk",
"no_appslist_found": "Geen app-lijsten gevonden", "no_appslist_found": "Geen app-lijsten gevonden",
"no_internet_connection": "Server is niet verbonden met het internet", "no_internet_connection": "Server is niet verbonden met het internet",
"no_ipv6_connectivity": "IPv6-stack is onbeschikbaar", "no_ipv6_connectivity": "IPv6-stack is onbeschikbaar",
"path_removal_failed": "Kan pad niet verwijderen {:s}", "path_removal_failed": "Kan pad niet verwijderen {:s}",
"pattern_email": "Moet een geldig emailadres bevatten (bv. abc@example.org)", "pattern_email": "Moet een geldig emailadres bevatten (bv. abc@example.org)",
"pattern_listname": "Slechts cijfers, letters en '_' zijn toegelaten", "pattern_listname": "Slechts cijfers, letters en '_' zijn toegelaten",
"pattern_mailbox_quota": "Mailbox quota moet een waarde bevatten met b/k/M/G/T erachter of 0 om geen quota in te stellen", "pattern_mailbox_quota": "Mailbox quota moet een waarde bevatten met b/k/M/G/T erachter of 0 om geen quota in te stellen",
"pattern_password": "Wachtwoord moet tenminste 3 karakters lang zijn", "pattern_password": "Wachtwoord moet tenminste 3 karakters lang zijn",
"port_already_closed": "Poort {} is al gesloten voor {:s} verbindingen", "port_already_closed": "Poort {port:d} is al gesloten voor {ip_version:s} verbindingen",
"port_already_opened": "Poort {} is al open voor {:s} verbindingen", "port_already_opened": "Poort {port:d} is al open voor {ip_version:s} verbindingen",
"port_available": "Poort {} is beschikbaar", "port_available": "Poort {port:d} is beschikbaar",
"port_unavailable": "Poort {} is niet beschikbaar", "port_unavailable": "Poort {port:d} is niet beschikbaar",
"restore_app_failed": "De app '{app:s}' kon niet worden terug gezet", "restore_app_failed": "De app '{app:s}' kon niet worden terug gezet",
"restore_hook_unavailable": "De restauration hook '{hook:s}' is niet beschikbaar op dit systeem", "restore_hook_unavailable": "De restauration hook '{hook:s}' is niet beschikbaar op dit systeem",
"service_add_failed": "Kan service '{:s}' niet toevoegen", "service_add_failed": "Kan service '{service:s}' niet toevoegen",
"service_already_started": "Service '{:s}' draait al", "service_already_started": "Service '{service:s}' draait al",
"service_cmd_exec_failed": "Kan '{:s}' niet uitvoeren", "service_cmd_exec_failed": "Kan '{command:s}' niet uitvoeren",
"service_disabled": "Service '{:s}' is uitgeschakeld", "service_disabled": "Service '{service:s}' is uitgeschakeld",
"service_remove_failed": "Kan service '{:s}' niet verwijderen", "service_remove_failed": "Kan service '{service:s}' niet verwijderen",
"service_removed": "Service werd verwijderd", "service_removed": "Service werd verwijderd",
"service_stop_failed": "Kan service '{:s}' niet stoppen", "service_stop_failed": "Kan service '{service:s}' niet stoppen",
"service_unknown": "De service '{:s}' bestaat niet", "service_unknown": "De service '{service:s}' bestaat niet",
"show_diff": "Let op de volgende verschillen zijn:\n{diff:s}", "show_diff": "Let op de volgende verschillen zijn:\n{diff:s}",
"unexpected_error": "Er is een onbekende fout opgetreden", "unexpected_error": "Er is een onbekende fout opgetreden",
"unrestore_app": "App '{app:s}' wordt niet teruggezet", "unrestore_app": "App '{app:s}' wordt niet teruggezet",
"updating_apt_cache": "Lijst van beschikbare pakketen wordt bijgewerkt", "updating_apt_cache": "Lijst van beschikbare pakketen wordt bijgewerkt",
"upgrade_complete": "Upgrade voltooid", "upgrade_complete": "Upgrade voltooid",
"upgrading_packages": "Pakketten worden geüpdate...", "upgrading_packages": "Pakketten worden geüpdate...",
"upnp_dev_not_found": "Geen UPnP apparaten gevonden", "upnp_dev_not_found": "Geen UPnP apparaten gevonden",
"upnp_disabled": "UPnP successvol uitgeschakeld", "upnp_disabled": "UPnP successvol uitgeschakeld",
"upnp_enabled": "UPnP succesvol ingeschakeld", "upnp_enabled": "UPnP succesvol ingeschakeld",
"upnp_port_open_failed": "Kan UPnP poorten niet openen", "upnp_port_open_failed": "Kan UPnP poorten niet openen",
"user_deleted": "Gebruiker werd verwijderd", "user_deleted": "Gebruiker werd verwijderd",
"user_home_creation_failed": "Kan de map voor deze gebruiker niet aanmaken", "user_home_creation_failed": "Kan de map voor deze gebruiker niet aanmaken",
"user_unknown": "Gebruikersnaam is onbekend", "user_unknown": "Gebruikersnaam is onbekend",
"user_update_failed": "Kan gebruiker niet bijwerken", "user_update_failed": "Kan gebruiker niet bijwerken",
"yunohost_configured": "YunoHost configuratie is OK" "yunohost_configured": "YunoHost configuratie is OK"
} }

View file

@ -1,148 +1,148 @@
{ {
"action_invalid": "Acção Inválida '{:s}'", "action_invalid": "Acção Inválida '{action:s}'",
"admin_password": "Senha de administração", "admin_password": "Senha de administração",
"admin_password_change_failed": "Não foi possível alterar a senha", "admin_password_change_failed": "Não foi possível alterar a senha",
"admin_password_changed": "Senha de administração alterada com êxito", "admin_password_changed": "Senha de administração alterada com êxito",
"app_already_installed": "{:s} já está instalada", "app_already_installed": "{app:s} já está instalada",
"app_extraction_failed": "Não foi possível extrair os ficheiros para instalação", "app_extraction_failed": "Não foi possível extrair os ficheiros para instalação",
"app_id_invalid": "ID da aplicação invélida", "app_id_invalid": "ID da aplicação invélida",
"app_install_files_invalid": "Ficheiros para instalação corrompidos", "app_install_files_invalid": "Ficheiros para instalação corrompidos",
"app_location_already_used": "Já existe uma aplicação instalada neste diretório", "app_location_already_used": "Já existe uma aplicação instalada neste diretório",
"app_location_install_failed": "Não foi possível instalar a aplicação neste diretório", "app_location_install_failed": "Não foi possível instalar a aplicação neste diretório",
"app_manifest_invalid": "Manifesto da aplicação inválido", "app_manifest_invalid": "Manifesto da aplicação inválido",
"app_no_upgrade": "Não existem aplicações para atualizar", "app_no_upgrade": "Não existem aplicações para atualizar",
"app_not_installed": "{:s} não está instalada", "app_not_installed": "{app:s} não está instalada",
"app_recent_version_required": "{:s} requer uma versão mais recente da moulinette", "app_recent_version_required": "{:s} requer uma versão mais recente da moulinette",
"app_removed": "{:s} removida com êxito", "app_removed": "{app:s} removida com êxito",
"app_sources_fetch_failed": "Impossível obter os códigos fontes", "app_sources_fetch_failed": "Impossível obter os códigos fontes",
"app_unknown": "Aplicação desconhecida", "app_unknown": "Aplicação desconhecida",
"app_upgrade_failed": "Unable to upgrade all apps", "app_upgrade_failed": "Unable to upgrade all apps",
"app_upgraded": "{:s} atualizada com êxito", "app_upgraded": "{app:s} atualizada com êxito",
"appslist_fetched": "Lista de aplicações processada com êxito", "appslist_fetched": "Lista de aplicações processada com êxito",
"appslist_removed": "Lista de aplicações removida com êxito", "appslist_removed": "Lista de aplicações removida com êxito",
"appslist_retrieve_error": "Não foi possível obter a lista de aplicações remotas", "appslist_retrieve_error": "Não foi possível obter a lista de aplicações remotas",
"appslist_unknown": "Lista de aplicaçoes desconhecida", "appslist_unknown": "Lista de aplicaçoes desconhecida",
"ask_current_admin_password": "Senha de administração atual", "ask_current_admin_password": "Senha de administração atual",
"ask_email": "Correio eletrónico", "ask_email": "Correio eletrónico",
"ask_firstname": "Primeiro nome", "ask_firstname": "Primeiro nome",
"ask_lastname": "Último nome", "ask_lastname": "Último nome",
"ask_list_to_remove": "Lista para remover", "ask_list_to_remove": "Lista para remover",
"ask_main_domain": "Domínio principal", "ask_main_domain": "Domínio principal",
"ask_new_admin_password": "Senha de administração nova", "ask_new_admin_password": "Senha de administração nova",
"ask_password": "Senha", "ask_password": "Senha",
"backup_complete": "Backup completo", "backup_complete": "Backup completo",
"backup_creating_archive": "A criar ficheiro de backup...", "backup_creating_archive": "A criar ficheiro de backup...",
"backup_invalid_archive": "Arquivo de backup inválido", "backup_invalid_archive": "Arquivo de backup inválido",
"backup_output_directory_not_empty": "A pasta de destino não se encontra vazia", "backup_output_directory_not_empty": "A pasta de destino não se encontra vazia",
"custom_app_url_required": "Deve proporcionar uma URL para atualizar a sua aplicação personalizada {:s}", "custom_app_url_required": "Deve proporcionar uma URL para atualizar a sua aplicação personalizada {app:s}",
"custom_appslist_name_required": "Deve fornecer um nome para a sua lista de aplicações personalizada", "custom_appslist_name_required": "Deve fornecer um nome para a sua lista de aplicações personalizada",
"domain_cert_gen_failed": "Não foi possível gerar o certificado", "domain_cert_gen_failed": "Não foi possível gerar o certificado",
"domain_created": "Domínio criado com êxito", "domain_created": "Domínio criado com êxito",
"domain_creation_failed": "Não foi possível criar o domínio", "domain_creation_failed": "Não foi possível criar o domínio",
"domain_deleted": "Domínio removido com êxito", "domain_deleted": "Domínio removido com êxito",
"domain_deletion_failed": "Não foi possível eliminar o domínio", "domain_deletion_failed": "Não foi possível eliminar o domínio",
"domain_dyndns_already_subscribed": "Já subscreveu um domínio DynDNS", "domain_dyndns_already_subscribed": "Já subscreveu um domínio DynDNS",
"domain_dyndns_invalid": "Domínio inválido para ser utilizado com DynDNS", "domain_dyndns_invalid": "Domínio inválido para ser utilizado com DynDNS",
"domain_dyndns_root_unknown": "Domínio root (administrador) DynDNS desconhecido", "domain_dyndns_root_unknown": "Domínio root (administrador) DynDNS desconhecido",
"domain_exists": "O domínio já existe", "domain_exists": "O domínio já existe",
"domain_uninstall_app_first": "Existem uma ou mais aplicações instaladas neste domínio. Por favor desinstale-as antes de proceder com a remoção do domínio.", "domain_uninstall_app_first": "Existem uma ou mais aplicações instaladas neste domínio. Por favor desinstale-as antes de proceder com a remoção do domínio.",
"domain_unknown": "Domínio desconhecido", "domain_unknown": "Domínio desconhecido",
"domain_zone_exists": "Ficheiro para zona DMZ já existe", "domain_zone_exists": "Ficheiro para zona DMZ já existe",
"domain_zone_not_found": "Ficheiro para zona DMZ não encontrado no domínio {:s}", "domain_zone_not_found": "Ficheiro para zona DMZ não encontrado no domínio {:s}",
"done": "Concluído.", "done": "Concluído.",
"downloading": "Transferência em curso...", "downloading": "Transferência em curso...",
"dyndns_cron_installed": "Gestor de tarefas cron DynDNS instalado com êxito", "dyndns_cron_installed": "Gestor de tarefas cron DynDNS instalado com êxito",
"dyndns_cron_remove_failed": "Não foi possível remover o gestor de tarefas cron DynDNS", "dyndns_cron_remove_failed": "Não foi possível remover o gestor de tarefas cron DynDNS",
"dyndns_cron_removed": "Gestor de tarefas cron DynDNS removido com êxito", "dyndns_cron_removed": "Gestor de tarefas cron DynDNS removido com êxito",
"dyndns_ip_update_failed": "Não foi possível atualizar o endereço IP a partir de DynDNS", "dyndns_ip_update_failed": "Não foi possível atualizar o endereço IP a partir de DynDNS",
"dyndns_ip_updated": "Endereço IP atualizado com êxito a partir de DynDNS", "dyndns_ip_updated": "Endereço IP atualizado com êxito a partir de DynDNS",
"dyndns_key_generating": "A chave DNS está a ser gerada, isto pode demorar um pouco...", "dyndns_key_generating": "A chave DNS está a ser gerada, isto pode demorar um pouco...",
"dyndns_registered": "Dom+inio DynDNS registado com êxito", "dyndns_registered": "Dom+inio DynDNS registado com êxito",
"dyndns_registration_failed": "Não foi possível registar o domínio DynDNS: {:s}", "dyndns_registration_failed": "Não foi possível registar o domínio DynDNS: {error:s}",
"dyndns_unavailable": "Subdomínio DynDNS indisponível", "dyndns_unavailable": "Subdomínio DynDNS indisponível",
"executing_script": "A executar o script...", "executing_script": "A executar o script...",
"extracting": "Extração em curso...", "extracting": "Extração em curso...",
"field_invalid": "Campo inválido '{:s}'", "field_invalid": "Campo inválido '{:s}'",
"firewall_reloaded": "Firewall recarregada com êxito", "firewall_reloaded": "Firewall recarregada com êxito",
"hook_argument_missing": "Argumento em falta '{:s}'", "hook_argument_missing": "Argumento em falta '{:s}'",
"hook_choice_invalid": "Escolha inválida '{:s}'", "hook_choice_invalid": "Escolha inválida '{:s}'",
"installation_complete": "Instalação concluída", "installation_complete": "Instalação concluída",
"installation_failed": "A instalação falhou", "installation_failed": "A instalação falhou",
"iptables_unavailable": "Não pode alterar aqui a iptables. Ou o seu kernel não o suporta ou está num espaço reservado.", "iptables_unavailable": "Não pode alterar aqui a iptables. Ou o seu kernel não o suporta ou está num espaço reservado.",
"ldap_initialized": "LDAP inicializada com êxito", "ldap_initialized": "LDAP inicializada com êxito",
"license_undefined": "indefinido", "license_undefined": "indefinido",
"mail_alias_remove_failed": "Não foi possível remover a etiqueta de correio '{:s}'", "mail_alias_remove_failed": "Não foi possível remover a etiqueta de correio '{mail:s}'",
"mail_domain_unknown": "Domínio de endereço de correio desconhecido '{:s}'", "mail_domain_unknown": "Domínio de endereço de correio desconhecido '{domain:s}'",
"mail_forward_remove_failed": "Não foi possível remover o reencaminhamento de correio '{:s}'", "mail_forward_remove_failed": "Não foi possível remover o reencaminhamento de correio '{mail:s}'",
"maindomain_change_failed": "Incapaz alterar o domínio raiz", "maindomain_change_failed": "Incapaz alterar o domínio raiz",
"maindomain_changed": "Domínio raiz alterado com êxito", "maindomain_changed": "Domínio raiz alterado com êxito",
"monitor_disabled": "Monitorização do servidor parada com êxito", "monitor_disabled": "Monitorização do servidor parada com êxito",
"monitor_enabled": "Monitorização do servidor ativada com êxito", "monitor_enabled": "Monitorização do servidor ativada com êxito",
"monitor_glances_con_failed": "Não foi possível ligar ao servidor Glances", "monitor_glances_con_failed": "Não foi possível ligar ao servidor Glances",
"monitor_not_enabled": "A monitorização do servidor não está ativa", "monitor_not_enabled": "A monitorização do servidor não está ativa",
"monitor_period_invalid": "Período de tempo inválido", "monitor_period_invalid": "Período de tempo inválido",
"monitor_stats_file_not_found": "Ficheiro de estatísticas não encontrado", "monitor_stats_file_not_found": "Ficheiro de estatísticas não encontrado",
"monitor_stats_no_update": "Não existem estatísticas de monitorização para atualizar", "monitor_stats_no_update": "Não existem estatísticas de monitorização para atualizar",
"monitor_stats_period_unavailable": "Não existem estatísticas disponíveis para este período", "monitor_stats_period_unavailable": "Não existem estatísticas disponíveis para este período",
"mountpoint_unknown": "Ponto de montagem desconhecido", "mountpoint_unknown": "Ponto de montagem desconhecido",
"mysql_db_creation_failed": "Criação da base de dados MySQL falhou", "mysql_db_creation_failed": "Criação da base de dados MySQL falhou",
"mysql_db_init_failed": "Inicialização da base de dados MySQL falhou", "mysql_db_init_failed": "Inicialização da base de dados MySQL falhou",
"mysql_db_initialized": "Base de dados MySQL iniciada com êxito", "mysql_db_initialized": "Base de dados MySQL iniciada com êxito",
"new_domain_required": "Deve escrever um novo domínio principal", "new_domain_required": "Deve escrever um novo domínio principal",
"no_appslist_found": "Não foi encontrada a lista de aplicações", "no_appslist_found": "Não foi encontrada a lista de aplicações",
"no_internet_connection": "O servidor não está ligado à Internet", "no_internet_connection": "O servidor não está ligado à Internet",
"packages_no_upgrade": "Não existem pacotes para atualizar", "packages_no_upgrade": "Não existem pacotes para atualizar",
"packages_upgrade_critical_later": "Os pacotes críticos ({:s}) serão atualizados depois", "packages_upgrade_critical_later": "Os pacotes críticos ({packages:s}) serão atualizados depois",
"packages_upgrade_failed": "Não foi possível atualizar todos os pacotes", "packages_upgrade_failed": "Não foi possível atualizar todos os pacotes",
"path_removal_failed": "Incapaz remover o caminho {:s}", "path_removal_failed": "Incapaz remover o caminho {:s}",
"pattern_domain": "Deve ser um nome de domínio válido (p.e. meu-dominio.org)", "pattern_domain": "Deve ser um nome de domínio válido (p.e. meu-dominio.org)",
"pattern_email": "Deve ser um endereço de correio válido (p.e. alguem@dominio.org)", "pattern_email": "Deve ser um endereço de correio válido (p.e. alguem@dominio.org)",
"pattern_firstname": "Deve ser um primeiro nome válido", "pattern_firstname": "Deve ser um primeiro nome válido",
"pattern_lastname": "Deve ser um último nome válido", "pattern_lastname": "Deve ser um último nome válido",
"pattern_listname": "Apenas são permitidos caracteres alfanuméricos e travessões", "pattern_listname": "Apenas são permitidos caracteres alfanuméricos e travessões",
"pattern_password": "Deve ter no mínimo 3 caracteres", "pattern_password": "Deve ter no mínimo 3 caracteres",
"pattern_port": "Deve ser um número de porta válido (entre 0-65535)", "pattern_port": "Deve ser um número de porta válido (entre 0-65535)",
"pattern_username": "Must be lower-case alphanumeric and underscore characters only", "pattern_username": "Must be lower-case alphanumeric and underscore characters only",
"restore_confirm_yunohost_installed": "Quer mesmo restaurar um sistema já instalado? [{answers:s}]", "restore_confirm_yunohost_installed": "Quer mesmo restaurar um sistema já instalado? [{answers:s}]",
"service_add_failed": "Incapaz adicionar serviço '{:s}'", "service_add_failed": "Incapaz adicionar serviço '{service:s}'",
"service_added": "Serviço adicionado com êxito", "service_added": "Serviço adicionado com êxito",
"service_already_started": "O serviço '{:s}' já está em execussão", "service_already_started": "O serviço '{service:s}' já está em execussão",
"service_already_stopped": "O serviço '{:s}' já está parado", "service_already_stopped": "O serviço '{service:s}' já está parado",
"service_cmd_exec_failed": "Incapaz executar o comando '{:s}'", "service_cmd_exec_failed": "Incapaz executar o comando '{command:s}'",
"service_disable_failed": "Incapaz desativar o serviço '{:s}'", "service_disable_failed": "Incapaz desativar o serviço '{service:s}'",
"service_disabled": "O serviço '{:s}' foi desativado com êxito", "service_disabled": "O serviço '{service:s}' foi desativado com êxito",
"service_enable_failed": "Incapaz de ativar o serviço '{:s}'", "service_enable_failed": "Incapaz de ativar o serviço '{service:s}'",
"service_enabled": "Serviço '{:s}' ativado com êxito", "service_enabled": "Serviço '{service:s}' ativado com êxito",
"service_no_log": "Não existem registos para mostrar do serviço '{:s}'", "service_no_log": "Não existem registos para mostrar do serviço '{service:s}'",
"service_remove_failed": "Incapaz de remover o serviço '{:s}'", "service_remove_failed": "Incapaz de remover o serviço '{service:s}'",
"service_removed": "Serviço eliminado com êxito", "service_removed": "Serviço eliminado com êxito",
"service_start_failed": "Não foi possível iniciar o serviço '{:s}'", "service_start_failed": "Não foi possível iniciar o serviço '{service:s}'",
"service_started": "O serviço '{:s} foi iniciado com êxito", "service_started": "O serviço '{service:s}' foi iniciado com êxito",
"service_status_failed": "Incapaz determinar o estado do serviço '{:s}'", "service_status_failed": "Incapaz determinar o estado do serviço '{service:s}'",
"service_stop_failed": "Incapaz parar o serviço '{:s}", "service_stop_failed": "Incapaz parar o serviço '{service:s}'",
"service_stopped": "O serviço '{:s}' foi parado com êxito", "service_stopped": "O serviço '{service:s}' foi parado com êxito",
"service_unknown": "Serviço desconhecido '{:s}'", "service_unknown": "Serviço desconhecido '{service:s}'",
"ssowat_conf_generated": "Configuração SSOwat gerada com êxito", "ssowat_conf_generated": "Configuração SSOwat gerada com êxito",
"ssowat_conf_updated": "Configuração persistente SSOwat atualizada com êxito", "ssowat_conf_updated": "Configuração persistente SSOwat atualizada com êxito",
"system_upgraded": "Sistema atualizado com êxito", "system_upgraded": "Sistema atualizado com êxito",
"system_username_exists": "O utilizador já existe no registo do sistema", "system_username_exists": "O utilizador já existe no registo do sistema",
"unexpected_error": "Ocorreu um erro inesperado", "unexpected_error": "Ocorreu um erro inesperado",
"unit_unknown": "Unidade desconhecida '{:s}'", "unit_unknown": "Unidade desconhecida '{unit:s}'",
"update_cache_failed": "Não foi possível atualizar os cabeçalhos APT", "update_cache_failed": "Não foi possível atualizar os cabeçalhos APT",
"updating_apt_cache": "A atualizar a lista de pacotes disponíveis...", "updating_apt_cache": "A atualizar a lista de pacotes disponíveis...",
"upgrade_complete": "Atualização completa", "upgrade_complete": "Atualização completa",
"upgrading_packages": "Atualização de pacotes em curso...", "upgrading_packages": "Atualização de pacotes em curso...",
"user_created": "Utilizador criado com êxito", "user_created": "Utilizador criado com êxito",
"user_creation_failed": "Não foi possível criar o utilizador", "user_creation_failed": "Não foi possível criar o utilizador",
"user_deleted": "Utilizador eliminado com êxito", "user_deleted": "Utilizador eliminado com êxito",
"user_deletion_failed": "Incapaz eliminar o utilizador", "user_deletion_failed": "Incapaz eliminar o utilizador",
"user_info_failed": "Incapaz obter informações sobre o utilizador", "user_info_failed": "Incapaz obter informações sobre o utilizador",
"user_unknown": "Utilizador desconhecido", "user_unknown": "Utilizador desconhecido",
"user_update_failed": "Não foi possível atualizar o utilizador", "user_update_failed": "Não foi possível atualizar o utilizador",
"user_updated": "Utilizador atualizado com êxito", "user_updated": "Utilizador atualizado com êxito",
"yunohost_already_installed": "AYunoHost já está instalado", "yunohost_already_installed": "AYunoHost já está instalado",
"yunohost_ca_creation_failed": "Incapaz criar o certificado de autoridade", "yunohost_ca_creation_failed": "Incapaz criar o certificado de autoridade",
"yunohost_configured": "YunoHost configurada com êxito", "yunohost_configured": "YunoHost configurada com êxito",
"yunohost_installing": "A instalar a YunoHost...", "yunohost_installing": "A instalar a YunoHost...",
"yunohost_not_installed": "YunoHost ainda não está corretamente configurado. Por favor execute as 'ferramentas pós-instalação yunohost'." "yunohost_not_installed": "YunoHost ainda não está corretamente configurado. Por favor execute as 'ferramentas pós-instalação yunohost'."
} }

View file

@ -1413,12 +1413,24 @@ def _encode_string(value):
def _check_manifest_requirements(manifest): def _check_manifest_requirements(manifest):
"""Check if required packages are met from the manifest""" """Check if required packages are met from the manifest"""
requirements = manifest.get('requirements', dict()) requirements = manifest.get('requirements', dict())
# FIXME: Deprecate min_version key # FIXME: Deprecate min_version key
if 'min_version' in manifest: if 'min_version' in manifest:
requirements['yunohost'] = '>> {0}'.format(manifest['min_version']) requirements['yunohost'] = '>> {0}'.format(manifest['min_version'])
logger.debug("the manifest key 'min_version' is deprecated, " logger.debug("the manifest key 'min_version' is deprecated, "
"use 'requirements' instead.") "use 'requirements' instead.")
if not requirements:
# Validate multi-instance app
if manifest.get('multi_instance', False):
# Handle backward-incompatible change introduced in yunohost >= 2.3.6
# See https://dev.yunohost.org/issues/156
yunohost_req = requirements.get('yunohost', None)
if (not yunohost_req or
not packages.SpecifierSet(yunohost_req) & '>= 2.3.6'):
raise MoulinetteError(errno.EINVAL, '{0}{1}'.format(
m18n.g('colon', m18n.n('app_incompatible')),
m18n.n('app_package_need_update')))
elif not requirements:
return return
logger.info(m18n.n('app_requirements_checking')) logger.info(m18n.n('app_requirements_checking'))
@ -1429,7 +1441,8 @@ def _check_manifest_requirements(manifest):
*requirements.keys(), strict=True, as_dict=True) *requirements.keys(), strict=True, as_dict=True)
except packages.PackageException as e: except packages.PackageException as e:
raise MoulinetteError(errno.EINVAL, raise MoulinetteError(errno.EINVAL,
m18n.n('app_requirements_failed', err=str(e))) m18n.n('app_requirements_failed',
error=str(e)))
# Iterate over requirements # Iterate over requirements
for pkgname, spec in requirements.items(): for pkgname, spec in requirements.items():

View file

@ -39,7 +39,9 @@ from moulinette.core import MoulinetteError
from moulinette.utils import filesystem from moulinette.utils import filesystem
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from yunohost.app import app_info, app_ssowatconf, _is_installed, _parse_app_instance_name from yunohost.app import (
app_info, app_ssowatconf, _is_installed, _parse_app_instance_name
)
from yunohost.hook import ( from yunohost.hook import (
hook_info, hook_callback, hook_exec, custom_hook_folder hook_info, hook_callback, hook_exec, custom_hook_folder
) )
@ -384,11 +386,11 @@ def backup_restore(auth, name, hooks=[], ignore_hooks=False,
else: else:
# Retrieve the domain from the backup # Retrieve the domain from the backup
try: try:
with open("%s/yunohost/current_host" % tmp_dir, 'r') as f: with open("%s/conf/ynh/current_host" % tmp_dir, 'r') as f:
domain = f.readline().rstrip() domain = f.readline().rstrip()
except IOError: except IOError:
logger.debug("unable to retrieve domain from " logger.debug("unable to retrieve current_host from the backup",
"'%s/yunohost/current_host'", tmp_dir, exc_info=1) exc_info=1)
raise MoulinetteError(errno.EIO, m18n.n('backup_invalid_archive')) raise MoulinetteError(errno.EIO, m18n.n('backup_invalid_archive'))
logger.debug("executing the post-install...") logger.debug("executing the post-install...")

View file

@ -37,6 +37,8 @@ from urllib import urlopen
from moulinette.core import MoulinetteError from moulinette.core import MoulinetteError
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from yunohost.service import service_regen_conf
logger = getActionLogger('yunohost.domain') logger = getActionLogger('yunohost.domain')
@ -78,7 +80,6 @@ def domain_add(auth, domain, dyndns=False):
dyndns -- Subscribe to DynDNS dyndns -- Subscribe to DynDNS
""" """
from yunohost.service import service_regenconf
from yunohost.hook import hook_callback from yunohost.hook import hook_callback
attr_dict = { 'objectClass' : ['mailDomain', 'top'] } attr_dict = { 'objectClass' : ['mailDomain', 'top'] }
@ -157,10 +158,8 @@ def domain_add(auth, domain, dyndns=False):
try: try:
with open('/etc/yunohost/installed', 'r') as f: with open('/etc/yunohost/installed', 'r') as f:
service_regenconf(service='nginx') service_regen_conf(names=[
service_regenconf(service='metronome') 'nginx', 'metronome', 'dnsmasq', 'rmilter'])
service_regenconf(service='dnsmasq')
service_regenconf(service='rmilter')
os.system('yunohost app ssowatconf > /dev/null 2>&1') os.system('yunohost app ssowatconf > /dev/null 2>&1')
except IOError: pass except IOError: pass
except: except:
@ -183,7 +182,6 @@ def domain_remove(auth, domain, force=False):
force -- Force the domain removal force -- Force the domain removal
""" """
from yunohost.service import service_regenconf
from yunohost.hook import hook_callback from yunohost.hook import hook_callback
if not force and domain not in domain_list(auth)['domains']: if not force and domain not in domain_list(auth)['domains']:
@ -206,9 +204,7 @@ def domain_remove(auth, domain, force=False):
else: else:
raise MoulinetteError(errno.EIO, m18n.n('domain_deletion_failed')) raise MoulinetteError(errno.EIO, m18n.n('domain_deletion_failed'))
service_regenconf(service='nginx') service_regen_conf(names=['nginx', 'metronome', 'dnsmasq'])
service_regenconf(service='metronome')
service_regenconf(service='dnsmasq')
os.system('yunohost app ssowatconf > /dev/null 2>&1') os.system('yunohost app ssowatconf > /dev/null 2>&1')
hook_callback('post_domain_remove', args=[domain]) hook_callback('post_domain_remove', args=[domain])

View file

@ -176,6 +176,8 @@ def hook_list(action, list_by='name', show_info=False):
def _append_folder(d, folder): def _append_folder(d, folder):
# Iterate over and add hook from a folder # Iterate over and add hook from a folder
for f in os.listdir(folder + action): for f in os.listdir(folder + action):
if f[0] == '.' or f[-1] == '~':
continue
path = '%s%s/%s' % (folder, action, f) path = '%s%s/%s' % (folder, action, f)
priority, name = _extract_filename_parts(f) priority, name = _extract_filename_parts(f)
_append_hook(d, priority, name, path) _append_hook(d, priority, name, path)
@ -205,14 +207,22 @@ def hook_list(action, list_by='name', show_info=False):
return { 'hooks': result } return { 'hooks': result }
def hook_callback(action, hooks=[], args=None): def hook_callback(action, hooks=[], args=None, no_trace=False, chdir=None,
pre_callback=None, post_callback=None):
""" """
Execute all scripts binded to an action Execute all scripts binded to an action
Keyword argument: Keyword argument:
action -- Action name action -- Action name
hooks -- List of hooks names to execute hooks -- List of hooks names to execute
args -- Ordered list of arguments to pass to the script args -- Ordered list of arguments to pass to the scripts
no_trace -- Do not print each command that will be executed
chdir -- The directory from where the scripts will be executed
pre_callback -- An object to call before each script execution with
(name, priority, path, args) as arguments and which must return
the arguments to pass to the script
post_callback -- An object to call after each script execution with
(name, priority, path, succeed) as arguments
""" """
result = { 'succeed': {}, 'failed': {} } result = { 'succeed': {}, 'failed': {} }
@ -252,26 +262,34 @@ def hook_callback(action, hooks=[], args=None):
if not hooks_dict: if not hooks_dict:
return result return result
# Format arguments # Validate callbacks
if args is None: if not callable(pre_callback):
args = [] pre_callback = lambda name, priority, path, args: args
elif not isinstance(args, list): if not callable(post_callback):
args = [args] post_callback = lambda name, priority, path, succeed: None
# Iterate over hooks and execute them # Iterate over hooks and execute them
for priority in sorted(hooks_dict): for priority in sorted(hooks_dict):
for name, info in iter(hooks_dict[priority].items()): for name, info in iter(hooks_dict[priority].items()):
state = 'succeed' state = 'succeed'
filename = '%s-%s' % (priority, name) path = info['path']
try: try:
hook_exec(info['path'], args=args, raise_on_error=True) hook_args = pre_callback(name=name, priority=priority,
path=path, args=args)
hook_exec(path, args=hook_args, chdir=chdir,
no_trace=no_trace, raise_on_error=True)
except MoulinetteError as e: except MoulinetteError as e:
logger.error(str(e))
state = 'failed' state = 'failed'
logger.error(str(e))
post_callback(name=name, priority=priority, path=path,
succeed=False)
else:
post_callback(name=name, priority=priority, path=path,
succeed=True)
try: try:
result[state][name].append(info['path']) result[state][name].append(path)
except KeyError: except KeyError:
result[state][name] = [info['path']] result[state][name] = [path]
return result return result
@ -282,7 +300,7 @@ def hook_exec(path, args=None, raise_on_error=False, no_trace=False,
Keyword argument: Keyword argument:
path -- Path of the script to execute path -- Path of the script to execute
args -- A list of arguments to pass to the script args -- Ordered list of arguments to pass to the script
raise_on_error -- Raise if the script returns a non-zero exit code raise_on_error -- Raise if the script returns a non-zero exit code
no_trace -- Do not print each command that will be executed no_trace -- Do not print each command that will be executed
chdir -- The directory from where the script will be executed chdir -- The directory from where the script will be executed

View file

@ -30,20 +30,18 @@ import glob
import subprocess import subprocess
import errno import errno
import shutil import shutil
import difflib
import hashlib import hashlib
from difflib import unified_diff
from moulinette.core import MoulinetteError from moulinette.core import MoulinetteError
from moulinette.utils import log from moulinette.utils import log, filesystem
template_dir = os.getenv( from yunohost.hook import hook_list, hook_callback
'YUNOHOST_TEMPLATE_DIR',
'/usr/share/yunohost/templates'
) base_conf_path = '/home/yunohost.conf'
conf_backup_dir = os.getenv( backup_conf_dir = os.path.join(base_conf_path, 'backup')
'YUNOHOST_CONF_BACKUP_DIR', pending_conf_dir = os.path.join(base_conf_path, 'pending')
'/home/yunohost.backup/conffiles'
)
logger = log.getActionLogger('yunohost.service') logger = log.getActionLogger('yunohost.service')
@ -273,26 +271,196 @@ def service_log(name, number=50):
return result return result
def service_regenconf(service=None, force=False): def service_regen_conf(names=[], with_diff=False, force=False, dry_run=False,
list_pending=False):
""" """
Regenerate the configuration file(s) for a service and compare the result Regenerate the configuration file(s) for a service
with the existing configuration file.
Prints the differences between files if any.
Keyword argument: Keyword argument:
service -- Regenerate configuration for a specfic service names -- Services name to regenerate configuration of
force -- Override the current configuration with the newly generated with_diff -- Show differences in case of configuration changes
one, even if it has been modified force -- Override all manual modifications in configuration files
dry_run -- Show what would have been regenerated
list_pending -- List pending configuration files and exit
""" """
from yunohost.hook import hook_callback result = {}
if service is not None: # Return the list of pending conf
hook_callback('conf_regen', [service], args=[force]) if list_pending:
logger.success(m18n.n('service_configured', service=service)) pending_conf = _get_pending_conf(names)
else: if with_diff:
hook_callback('conf_regen', args=[force]) for service, conf_files in pending_conf.items():
logger.success(m18n.n('service_configured_all')) for system_path, pending_path in conf_files.items():
pending_conf[service][system_path] = {
'pending_conf': pending_path,
'diff': _get_files_diff(
system_path, pending_path, True),
}
return pending_conf
# Clean pending conf directory
shutil.rmtree(pending_conf_dir, ignore_errors=True)
filesystem.mkdir(pending_conf_dir, 0755, True)
# Format common hooks arguments
common_args = [1 if force else 0, 1 if dry_run else 0]
# Execute hooks for pre-regen
pre_args = ['pre',] + common_args
def _pre_call(name, priority, path, args):
# create the pending conf directory for the service
service_pending_path = os.path.join(pending_conf_dir, name)
filesystem.mkdir(service_pending_path, 0755, True, uid='admin')
# return the arguments to pass to the script
return pre_args + [service_pending_path,]
pre_result = hook_callback('conf_regen', names, pre_callback=_pre_call)
# Update the services name
names = pre_result['succeed'].keys()
if not names:
raise MoulinetteError(errno.EIO,
m18n.n('service_regenconf_failed',
services=', '.join(pre_result['failed'])))
# Set the processing method
_regen = _process_regen_conf if not dry_run else lambda *a, **k: True
# Iterate over services and process pending conf
for service, conf_files in _get_pending_conf(names).items():
logger.info(m18n.n(
'service_regenconf_pending_applying' if not dry_run else \
'service_regenconf_dry_pending_applying',
service=service))
conf_hashes = _get_conf_hashes(service)
succeed_regen = {}
failed_regen = {}
for system_path, pending_path in conf_files.items():
logger.debug("processing pending conf '%s' to system conf '%s'",
pending_path, system_path)
conf_status = None
regenerated = False
# Get the diff between files
conf_diff = _get_files_diff(
system_path, pending_path, True) if with_diff else None
# Check if the conf must be removed
to_remove = True if os.path.getsize(pending_path) == 0 else False
# Retrieve and calculate hashes
current_hash = conf_hashes.get(system_path, None)
system_hash = _calculate_hash(system_path)
new_hash = None if to_remove else _calculate_hash(pending_path)
# -> system conf does not exists
if not system_hash:
if to_remove:
logger.debug("> system conf is already removed")
os.remove(pending_path)
continue
if not current_hash or force:
if force:
logger.debug("> system conf has been manually removed")
conf_status = 'force-created'
else:
logger.debug("> system conf does not exist yet")
conf_status = 'created'
regenerated = _regen(
system_path, pending_path, save=False)
else:
logger.warning(m18n.n(
'service_conf_file_manually_removed',
conf=system_path))
conf_status = 'removed'
# -> system conf is not managed yet
elif not current_hash:
logger.debug("> system conf is not managed yet")
if system_hash == new_hash:
logger.debug("> no changes to system conf has been made")
conf_status = 'managed'
regenerated = True
elif force and to_remove:
regenerated = _regen(system_path)
conf_status = 'force-removed'
elif force:
regenerated = _regen(system_path, pending_path)
conf_status = 'force-updated'
else:
logger.warning(m18n.n('service_conf_file_not_managed',
conf=system_path))
conf_status = 'unmanaged'
# -> system conf has not been manually modified
elif system_hash == current_hash:
if to_remove:
regenerated = _regen(system_path)
conf_status = 'removed'
elif system_hash != new_hash:
regenerated = _regen(system_path, pending_path)
conf_status = 'updated'
else:
logger.debug("> system conf is already up-to-date")
os.remove(pending_path)
continue
else:
logger.debug("> system conf has been manually modified")
if force:
regenerated = _regen(system_path, pending_path)
conf_status = 'force-updated'
else:
logger.warning(m18n.n(
'service_conf_file_manually_modified',
conf=system_path))
conf_status = 'modified'
# Store the result
conf_result = {'status': conf_status}
if conf_diff is not None:
conf_result['diff'] = conf_diff
if regenerated:
succeed_regen[system_path] = conf_result
conf_hashes[system_path] = new_hash
if os.path.isfile(pending_path):
os.remove(pending_path)
else:
failed_regen[system_path] = conf_result
# Check for service conf changes
if not succeed_regen and not failed_regen:
logger.info(m18n.n('service_conf_up_to_date', service=service))
continue
elif not failed_regen:
logger.success(m18n.n(
'service_conf_updated' if not dry_run else \
'service_conf_would_be_updated',
service=service))
if succeed_regen and not dry_run:
_update_conf_hashes(service, conf_hashes)
# Append the service results
result[service] = {
'applied': succeed_regen,
'pending': failed_regen
}
# Return in case of dry run
if dry_run:
return result
# Execute hooks for post-regen
post_args = ['post',] + common_args
def _pre_call(name, priority, path, args):
# append coma-separated applied changes for the service
if name in result and result[name]['applied']:
regen_conf_files = ','.join(result[name]['applied'].keys())
else:
regen_conf_files = ''
return post_args + [regen_conf_files,]
hook_callback('conf_regen', names, pre_callback=_pre_call)
return result
def _run_service_command(action, service): def _run_service_command(action, service):
@ -380,175 +548,141 @@ def _tail(file, n, offset=None):
except IOError: return [] except IOError: return []
def _get_diff(string, filename): def _get_files_diff(orig_file, new_file, as_string=False, skip_header=True):
""" """Compare two files and return the differences
Show differences between a string and a file's content
Keyword argument: Read and compare two files. The differences are returned either as a delta
string -- The string in unified diff format or a formatted string if as_string is True. The
filename -- The file to compare with header can also be removed if skip_header is True.
""" """
try: contents = [[], []]
with open(filename, 'r') as f: for i, path in enumerate((orig_file, new_file)):
file_lines = f.readlines() try:
with open(path, 'r') as f:
contents[i] = f.readlines()
except IOError:
pass
string = string + '\n' # Compare files and format output
new_lines = string.splitlines(True) diff = unified_diff(contents[0], contents[1])
if file_lines: if skip_header:
while '\n' == file_lines[-1]: for i in range(2):
del file_lines[-1] try:
return difflib.unified_diff(file_lines, new_lines) next(diff)
except IOError: return [] except:
break
if as_string:
result = ''.join(line for line in diff)
return result.rstrip()
return diff
def _hash(filename): def _calculate_hash(path):
""" """Calculate the MD5 hash of a file"""
Calculate a MD5 hash of a file
Keyword argument:
filename -- The file to hash
"""
hasher = hashlib.md5() hasher = hashlib.md5()
try: try:
with open(filename, 'rb') as f: with open(path, 'rb') as f:
buf = f.read() hasher.update(f.read())
hasher.update(buf)
return hasher.hexdigest() return hasher.hexdigest()
except IOError: except IOError:
return 'no hash yet' return None
def service_saferemove(service, conf_file, force=False): def _get_pending_conf(services=[]):
""" """Get pending configuration for service(s)
Check if the specific file has been modified before removing it.
Backup the file in /home/yunohost.backup
Keyword argument: Iterate over the pending configuration directory for given service(s) - or
service -- Service name of the file to delete all if empty - and look for files inside. Each file is considered as a
conf_file -- The file to write pending configuration file and therefore must be in the same directory
force -- Force file deletion tree than the system file that it replaces.
The result is returned as a dict of services with pending configuration as
key and a dict of `system_conf_path` => `pending_conf_path` as value.
""" """
deleted = False result = {}
if not os.path.isdir(pending_conf_dir):
return result
if not services:
services = os.listdir(pending_conf_dir)
for name in services:
service_conf = {}
service_pending_path = os.path.join(pending_conf_dir, name)
path_index = len(service_pending_path)
for root, dirs, files in os.walk(service_pending_path):
for filename in files:
pending_path = os.path.join(root, filename)
service_conf[pending_path[path_index:]] = pending_path
if service_conf:
result[name] = service_conf
return result
def _get_conf_hashes(service):
"""Get the registered conf hashes for a service"""
try:
return _get_services()[service]['conffiles']
except:
logger.debug("unable to retrieve conf hashes for %s",
service, exc_info=1)
return {}
def _update_conf_hashes(service, hashes):
"""Update the registered conf hashes for a service"""
logger.debug("updating conf hashes for '%s' with: %s",
service, hashes)
services = _get_services() services = _get_services()
service_conf = services.get(service, {})
if not os.path.exists(conf_file): service_conf['conffiles'] = hashes
try: services[service] = service_conf
del services[service]['conffiles'][conf_file]
except KeyError: pass
return True
# Backup existing file
date = time.strftime("%Y%m%d.%H%M%S")
conf_backup_file = conf_backup_dir + conf_file +'-'+ date
process = subprocess.Popen(
['install', '-D', conf_file, conf_backup_file]
)
process.wait()
# Retrieve hashes
if not 'conffiles' in services[service]:
services[service]['conffiles'] = {}
if conf_file in services[service]['conffiles']:
previous_hash = services[service]['conffiles'][conf_file]
else:
previous_hash = 'no hash yet'
current_hash = _hash(conf_file)
# Handle conflicts
if force or previous_hash == current_hash:
os.remove(conf_file)
try:
del services[service]['conffiles'][conf_file]
except KeyError: pass
deleted = True
else:
services[service]['conffiles'][conf_file] = previous_hash
os.remove(conf_backup_file)
if len(previous_hash) == 32 or previous_hash[-32:] != current_hash:
logger.warning(m18n.n('service_configuration_conflict',
file=conf_file))
_save_services(services) _save_services(services)
return deleted
def _process_regen_conf(system_conf, new_conf=None, save=True):
"""Regenerate a given system configuration file
def service_safecopy(service, new_conf_file, conf_file, force=False): Replace a given system configuration file by a new one or delete it if
""" new_conf is None. A backup of the file - keeping its directory tree - will
Check if the specific file has been modified and display differences. be done in the backup conf directory before any operation if save is True.
Stores the file hash in the services.yml file
Keyword argument:
service -- Service name attached to the conf file
new_conf_file -- Path to the desired conf file
conf_file -- Path to the targeted conf file
force -- Force file overriding
""" """
regenerated = False if save:
services = _get_services() backup_path = os.path.join(backup_conf_dir, '{0}-{1}'.format(
system_conf.lstrip('/'), time.strftime("%Y%m%d.%H%M%S")))
if not os.path.exists(new_conf_file): backup_dir = os.path.dirname(backup_path)
raise MoulinetteError(errno.EIO, m18n.n('no_such_conf_file', file=new_conf_file)) if not os.path.isdir(backup_dir):
filesystem.mkdir(backup_dir, 0755, True)
with open(new_conf_file, 'r') as f: shutil.copy2(system_conf, backup_path)
new_conf = ''.join(f.readlines()).rstrip() logger.info(m18n.n('service_conf_file_backed_up',
conf=system_conf, backup=backup_path))
# Backup existing file try:
date = time.strftime("%Y%m%d.%H%M%S") if not new_conf:
conf_backup_file = conf_backup_dir + conf_file +'-'+ date os.remove(system_conf)
if os.path.exists(conf_file): logger.info(m18n.n('service_conf_file_removed',
process = subprocess.Popen( conf=system_conf))
['install', '-D', conf_file, conf_backup_file] else:
) system_dir = os.path.dirname(system_conf)
process.wait() if not os.path.isdir(system_dir):
else: filesystem.mkdir(system_dir, 0755, True)
logger.info(m18n.n('service_add_configuration', file=conf_file)) shutil.copyfile(new_conf, system_conf)
logger.info(m18n.n('service_conf_file_updated',
# Add the service if it does not exist conf=system_conf))
if service not in services.keys(): except:
services[service] = {} if not new_conf and os.path.exists(system_conf):
logger.warning(m18n.n('service_conf_file_remove_failed',
# Retrieve hashes conf=system_conf),
if not 'conffiles' in services[service]: exc_info=1)
services[service]['conffiles'] = {} return False
elif new_conf:
if conf_file in services[service]['conffiles']: try:
previous_hash = services[service]['conffiles'][conf_file] copy_succeed = os.path.samefile(system_conf, new_conf)
else: except:
previous_hash = 'no hash yet' copy_succeed = False
finally:
current_hash = _hash(conf_file) if not copy_succeed:
diff = list(_get_diff(new_conf, conf_file)) logger.warning(m18n.n('service_conf_file_copy_failed',
conf=system_conf, new=new_conf),
# Handle conflicts exc_info=1)
if force or previous_hash == current_hash: return False
with open(conf_file, 'w') as f: f.write(new_conf) return True
new_hash = _hash(conf_file)
if previous_hash != new_hash:
regenerated = True
elif len(diff) == 0:
new_hash = _hash(conf_file)
else:
new_hash = previous_hash
if (len(previous_hash) == 32 or previous_hash[-32:] != current_hash):
logger.warning('{0} {1}'.format(
m18n.n('service_configuration_conflict', file=conf_file),
m18n.n('show_diff', diff=''.join(diff))))
# Remove the backup file if the configuration has not changed
if new_hash == previous_hash:
try:
os.remove(conf_backup_file)
except OSError: pass
services[service]['conffiles'][conf_file] = new_hash
_save_services(services)
return regenerated

View file

@ -43,7 +43,7 @@ from yunohost.app import app_fetchlist, app_info, app_upgrade, app_ssowatconf, a
from yunohost.domain import domain_add, domain_list, get_public_ip from yunohost.domain import domain_add, domain_list, get_public_ip
from yunohost.dyndns import dyndns_subscribe from yunohost.dyndns import dyndns_subscribe
from yunohost.firewall import firewall_upnp, firewall_reload from yunohost.firewall import firewall_upnp, firewall_reload
from yunohost.service import service_status, service_regenconf, service_log from yunohost.service import service_status, service_regen_conf, service_log
from yunohost.monitor import monitor_disk, monitor_network, monitor_system from yunohost.monitor import monitor_disk, monitor_network, monitor_system
from yunohost.utils.packages import ynh_packages_version from yunohost.utils.packages import ynh_packages_version
@ -152,7 +152,7 @@ def tools_maindomain(auth, old_domain=None, new_domain=None, dyndns=False):
try: try:
with open('/etc/yunohost/installed', 'r') as f: with open('/etc/yunohost/installed', 'r') as f:
service_regenconf() service_regen_conf()
except IOError: pass except IOError: pass
logger.success(m18n.n('maindomain_changed')) logger.success(m18n.n('maindomain_changed'))
@ -170,13 +170,10 @@ def tools_postinstall(domain, password, ignore_dyndns=False):
""" """
dyndns = not ignore_dyndns dyndns = not ignore_dyndns
try: # Do some checks at first
with open('/etc/yunohost/installed') as f: pass if os.path.isfile('/etc/yunohost/installed'):
except IOError: raise MoulinetteError(errno.EPERM,
logger.info(m18n.n('yunohost_installing')) m18n.n('yunohost_already_installed'))
else:
raise MoulinetteError(errno.EPERM, m18n.n('yunohost_already_installed'))
if len(domain.split('.')) >= 3 and not ignore_dyndns: if len(domain.split('.')) >= 3 and not ignore_dyndns:
try: try:
r = requests.get('https://dyndns.yunohost.org/domains') r = requests.get('https://dyndns.yunohost.org/domains')
@ -187,10 +184,23 @@ def tools_postinstall(domain, password, ignore_dyndns=False):
dyndomain = '.'.join(domain.split('.')[1:]) dyndomain = '.'.join(domain.split('.')[1:])
if dyndomain in dyndomains: if dyndomain in dyndomains:
if requests.get('https://dyndns.yunohost.org/test/%s' % domain).status_code == 200: if requests.get('https://dyndns.yunohost.org/test/%s' % domain).status_code == 200:
dyndns=True dyndns = True
else: else:
raise MoulinetteError(errno.EEXIST, raise MoulinetteError(errno.EEXIST,
m18n.n('dyndns_unavailable')) m18n.n('dyndns_unavailable'))
logger.info(m18n.n('yunohost_installing'))
# Instantiate LDAP Authenticator
auth = init_authenticator(('ldap', 'default'),
{'uri': "ldap://localhost:389",
'base_dn': "dc=yunohost,dc=org",
'user_rdn': "cn=admin" })
auth.authenticate('yunohost')
# Initialize LDAP for YunoHost
# TODO: Improve this part by integrate ldapinit into conf_regen hook
tools_ldapinit(auth)
# Create required folders # Create required folders
folders_to_create = [ folders_to_create = [
@ -230,6 +240,7 @@ def tools_postinstall(domain, password, ignore_dyndns=False):
os.system('chmod 644 /etc/ssowat/conf.json.persistent') os.system('chmod 644 /etc/ssowat/conf.json.persistent')
# Create SSL CA # Create SSL CA
service_regen_conf(['ssl'], force=True)
ssl_dir = '/usr/share/yunohost/yunohost-config/ssl/yunoCA' ssl_dir = '/usr/share/yunohost/yunohost-config/ssl/yunoCA'
command_list = [ command_list = [
'echo "01" > %s/serial' % ssl_dir, 'echo "01" > %s/serial' % ssl_dir,
@ -247,16 +258,6 @@ def tools_postinstall(domain, password, ignore_dyndns=False):
raise MoulinetteError(errno.EPERM, raise MoulinetteError(errno.EPERM,
m18n.n('yunohost_ca_creation_failed')) m18n.n('yunohost_ca_creation_failed'))
# Instantiate LDAP Authenticator
auth = init_authenticator(('ldap', 'default'),
{ 'uri': "ldap://localhost:389",
'base_dn': "dc=yunohost,dc=org",
'user_rdn': "cn=admin" })
auth.authenticate('yunohost')
# Initialize YunoHost LDAP base
tools_ldapinit(auth)
# New domain config # New domain config
tools_maindomain(auth, old_domain='yunohost.org', new_domain=domain, dyndns=dyndns) tools_maindomain(auth, old_domain='yunohost.org', new_domain=domain, dyndns=dyndns)
@ -275,7 +276,7 @@ def tools_postinstall(domain, password, ignore_dyndns=False):
os.system('update-rc.d yunohost-firewall enable') os.system('update-rc.d yunohost-firewall enable')
os.system('service yunohost-firewall start') os.system('service yunohost-firewall start')
service_regenconf(force=True) service_regen_conf(force=True)
logger.success(m18n.n('yunohost_configured')) logger.success(m18n.n('yunohost_configured'))
@ -503,4 +504,4 @@ def tools_diagnosis(auth, private=False):
# Domains # Domains
diagnosis['private']['domains'] = domain_list(auth)['domains'] diagnosis['private']['domains'] = domain_list(auth)['domains']
return diagnosis return diagnosis

View file

@ -98,17 +98,22 @@ class Specifier(object):
} }
def __init__(self, spec): def __init__(self, spec):
match = self._regex.search(spec) if isinstance(spec, basestring):
if not match: match = self._regex.search(spec)
raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec)) if not match:
raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
self._spec = ( self._spec = (
match.group("relation").strip(), match.group("relation").strip(),
match.group("version").strip(), match.group("version").strip(),
) )
elif isinstance(spec, self.__class__):
self._spec = spec._spec
else:
return NotImplemented
def __repr__(self): def __repr__(self):
return "<Specifier({1!r})>".format(str(self)) return "<Specifier({0!r})>".format(str(self))
def __str__(self): def __str__(self):
return "{0}{1}".format(*self._spec) return "{0}{1}".format(*self._spec)
@ -138,6 +143,12 @@ class Specifier(object):
return self._spec != other._spec return self._spec != other._spec
def __and__(self, other):
return self.intersection(other)
def __or__(self, other):
return self.union(other)
def _get_relation(self, op): def _get_relation(self, op):
return getattr(self, "_compare_{0}".format(self._relations[op])) return getattr(self, "_compare_{0}".format(self._relations[op]))
@ -167,7 +178,79 @@ class Specifier(object):
def __contains__(self, item): def __contains__(self, item):
return self.contains(item) return self.contains(item)
def intersection(self, other):
"""Make the intersection of two specifiers
Return a new `SpecifierSet` with version specifier(s) common to the
specifier and the other.
Example:
>>> Specifier('>= 2.2') & '>> 2.2.1' == '>> 2.2.1'
>>> Specifier('>= 2.2') & '<< 2.3' == '>= 2.2, << 2.3'
"""
if isinstance(other, basestring):
try:
other = self.__class__(other)
except InvalidSpecifier:
return NotImplemented
elif not isinstance(other, self.__class__):
return NotImplemented
# store spec parts for easy access
rel1, v1 = self.relation, self.version
rel2, v2 = other.relation, other.version
result = []
if other == self:
result = [other]
elif rel1 == '=':
result = [self] if v1 in other else None
elif rel2 == '=':
result = [other] if v2 in self else None
elif v1 == v2:
result = [other if rel1[1] == '=' else self]
elif v2 in self or v1 in other:
is_self_greater = version_compare(v1, v2) > 0
if rel1[0] == rel2[0]:
if rel1[0] == '>':
result = [self if is_self_greater else other]
else:
result = [other if is_self_greater else self]
else:
result = [self, other]
return SpecifierSet(result if result is not None else '')
def union(self, other):
"""Make the union of two version specifiers
Return a new `SpecifierSet` with version specifiers from the
specifier and the other.
Example:
>>> Specifier('>= 2.2') | '<< 2.3' == '>= 2.2, << 2.3'
"""
if isinstance(other, basestring):
try:
other = self.__class__(other)
except InvalidSpecifier:
return NotImplemented
elif not isinstance(other, self.__class__):
return NotImplemented
return SpecifierSet([self, other])
def contains(self, item): def contains(self, item):
"""Check if the specifier contains an other
Return whether the item is contained in the version specifier.
Example:
>>> '2.2.1' in Specifier('<< 2.3')
>>> '2.4' not in Specifier('<< 2.3')
"""
return self._get_relation(self.relation)(item, self.version) return self._get_relation(self.relation)(item, self.version)
@ -181,7 +264,9 @@ class SpecifierSet(object):
""" """
def __init__(self, specifiers): def __init__(self, specifiers):
specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] if isinstance(specifiers, basestring):
specifiers = [s.strip() for s in specifiers.split(",")
if s.strip()]
parsed = set() parsed = set()
for specifier in specifiers: for specifier in specifiers:
@ -190,7 +275,7 @@ class SpecifierSet(object):
self._specs = frozenset(parsed) self._specs = frozenset(parsed)
def __repr__(self): def __repr__(self):
return "<SpecifierSet({1!r})>".format(str(self)) return "<SpecifierSet({0!r})>".format(str(self))
def __str__(self): def __str__(self):
return ",".join(sorted(str(s) for s in self._specs)) return ",".join(sorted(str(s) for s in self._specs))
@ -199,14 +284,10 @@ class SpecifierSet(object):
return hash(self._specs) return hash(self._specs)
def __and__(self, other): def __and__(self, other):
if isinstance(other, basestring): return self.intersection(other)
other = SpecifierSet(other)
elif not isinstance(other, SpecifierSet):
return NotImplemented
specifier = SpecifierSet() def __or__(self, other):
specifier._specs = frozenset(self._specs | other._specs) return self.union(other)
return specifiers
def __eq__(self, other): def __eq__(self, other):
if isinstance(other, basestring): if isinstance(other, basestring):
@ -237,7 +318,69 @@ class SpecifierSet(object):
def __contains__(self, item): def __contains__(self, item):
return self.contains(item) return self.contains(item)
def intersection(self, other):
"""Make the intersection of two specifiers sets
Return a new `SpecifierSet` with version specifier(s) common to the
set and the other.
Example:
>>> SpecifierSet('>= 2.2') & '>> 2.2.1' == '>> 2.2.1'
>>> SpecifierSet('>= 2.2, << 2.4') & '<< 2.3' == '>= 2.2, << 2.3'
>>> SpecifierSet('>= 2.2, << 2.3') & '>= 2.4' == ''
"""
if isinstance(other, basestring):
other = SpecifierSet(other)
elif not isinstance(other, SpecifierSet):
return NotImplemented
specifiers = set(self._specs | other._specs)
intersection = [specifiers.pop()] if specifiers else []
for specifier in specifiers:
parsed = set()
for spec in intersection:
inter = spec & specifier
if not inter:
parsed.clear()
break
# TODO: validate with other specs in parsed
parsed.update(inter._specs)
intersection = parsed
if not intersection:
break
return SpecifierSet(intersection)
def union(self, other):
"""Make the union of two specifiers sets
Return a new `SpecifierSet` with version specifiers from the set
and the other.
Example:
>>> SpecifierSet('>= 2.2') | '<< 2.3' == '>= 2.2, << 2.3'
"""
if isinstance(other, basestring):
other = SpecifierSet(other)
elif not isinstance(other, SpecifierSet):
return NotImplemented
specifiers = SpecifierSet([])
specifiers._specs = frozenset(self._specs | other._specs)
return specifiers
def contains(self, item): def contains(self, item):
"""Check if the set contains a version specifier
Return whether the item is contained in all version specifiers.
Example:
>>> '2.2.1' in SpecifierSet('>= 2.2, << 2.3')
>>> '2.4' not in SpecifierSet('>= 2.2, << 2.3')
"""
return all( return all(
s.contains(item) s.contains(item)
for s in self._specs for s in self._specs