Merge pull request #717 from YunoHost/reorganize-helpers

[enh] Reorganize helpers
This commit is contained in:
Alexandre Aubin 2019-05-02 14:54:35 +02:00 committed by GitHub
commit 441157615e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 1219 additions and 1217 deletions

View file

@ -1,463 +0,0 @@
#!/bin/bash
# Use logrotate to manage the logfile
#
# usage: ynh_use_logrotate [--logfile=/log/file] [--nonappend] [--specific_user=user/group]
# | arg: -l, --logfile - absolute path of logfile
# | arg: -n, --nonappend - (optional) Replace the config file instead of appending this new config.
# | arg: -u, --specific_user : run logrotate as the specified user and group. If not specified logrotate is runned as root.
#
# If no --logfile is provided, /var/log/${app} will be used as default.
# logfile can be just a directory, or a full path to a logfile :
# /parentdir/logdir
# /parentdir/logdir/logfile.log
#
# It's possible to use this helper multiple times, each config will be added to
# the same logrotate config file. Unless you use the option --non-append
#
# Requires YunoHost version 2.6.4 or higher.
ynh_use_logrotate () {
# Declare an array to define the options of this helper.
local legacy_args=lnuya
declare -Ar args_array=( [l]=logfile= [n]=nonappend [u]=specific_user= [y]=non [a]=append )
# [y]=non [a]=append are only for legacy purpose, to not fail on the old option '--non-append'
local logfile
local nonappend
local specific_user
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local logfile="${logfile:-}"
local nonappend="${nonappend:-0}"
local specific_user="${specific_user:-}"
# LEGACY CODE - PRE GETOPTS
if [ $# -gt 0 ] && [ "$1" == "--non-append" ]; then
nonappend=1
# Destroy this argument for the next command.
shift
elif [ $# -gt 1 ] && [ "$2" == "--non-append" ]; then
nonappend=1
fi
if [ $# -gt 0 ] && [ "$(echo ${1:0:1})" != "-" ]; then
if [ "$(echo ${1##*.})" == "log" ]; then # Keep only the extension to check if it's a logfile
local logfile=$1 # In this case, focus logrotate on the logfile
else
local logfile=$1/*.log # Else, uses the directory and all logfile into it.
fi
fi
# LEGACY CODE
local customtee="tee -a"
if [ "$nonappend" -eq 1 ]; then
customtee="tee"
fi
if [ -n "$logfile" ]
then
if [ "$(echo ${logfile##*.})" != "log" ]; then # Keep only the extension to check if it's a logfile
local logfile="$logfile/*.log" # Else, uses the directory and all logfile into it.
fi
else
logfile="/var/log/${app}/*.log" # Without argument, use a defaut directory in /var/log
fi
local su_directive=""
if [[ -n $specific_user ]]; then
su_directive=" # Run logorotate as specific user - group
su ${specific_user%/*} ${specific_user#*/}"
fi
cat > ./${app}-logrotate << EOF # Build a config file for logrotate
$logfile {
# Rotate if the logfile exceeds 100Mo
size 100M
# Keep 12 old log maximum
rotate 12
# Compress the logs with gzip
compress
# Compress the log at the next cycle. So keep always 2 non compressed logs
delaycompress
# Copy and truncate the log to allow to continue write on it. Instead of move the log.
copytruncate
# Do not do an error if the log is missing
missingok
# Not rotate if the log is empty
notifempty
# Keep old logs in the same dir
noolddir
$su_directive
}
EOF
sudo mkdir -p $(dirname "$logfile") # Create the log directory, if not exist
cat ${app}-logrotate | sudo $customtee /etc/logrotate.d/$app > /dev/null # Append this config to the existing config file, or replace the whole config file (depending on $customtee)
}
# Remove the app's logrotate config.
#
# usage: ynh_remove_logrotate
#
# Requires YunoHost version 2.6.4 or higher.
ynh_remove_logrotate () {
if [ -e "/etc/logrotate.d/$app" ]; then
sudo rm "/etc/logrotate.d/$app"
fi
}
# Create a dedicated systemd config
#
# usage: ynh_add_systemd_config [--service=service] [--template=template]
# | arg: -s, --service - Service name (optionnal, $app by default)
# | arg: -t, --template - Name of template file (optionnal, this is 'systemd' by default, meaning ./conf/systemd.service will be used as template)
#
# This will use the template ../conf/<templatename>.service
# to generate a systemd config, by replacing the following keywords
# with global variables that should be defined before calling
# this helper :
#
# __APP__ by $app
# __FINALPATH__ by $final_path
#
# Requires YunoHost version 2.7.2 or higher.
ynh_add_systemd_config () {
# Declare an array to define the options of this helper.
local legacy_args=st
declare -Ar args_array=( [s]=service= [t]=template= )
local service
local template
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local service="${service:-$app}"
local template="${template:-systemd.service}"
finalsystemdconf="/etc/systemd/system/$service.service"
ynh_backup_if_checksum_is_different --file="$finalsystemdconf"
sudo cp ../conf/$template "$finalsystemdconf"
# To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable.
# Substitute in a nginx config file only if the variable is not empty
if test -n "${final_path:-}"; then
ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalsystemdconf"
fi
if test -n "${app:-}"; then
ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="$finalsystemdconf"
fi
ynh_store_file_checksum --file="$finalsystemdconf"
sudo chown root: "$finalsystemdconf"
sudo systemctl enable $service
sudo systemctl daemon-reload
}
# Remove the dedicated systemd config
#
# usage: ynh_remove_systemd_config [--service=service]
# | arg: -s, --service - Service name (optionnal, $app by default)
#
# Requires YunoHost version 2.7.2 or higher.
ynh_remove_systemd_config () {
# Declare an array to define the options of this helper.
local legacy_args=s
declare -Ar args_array=( [s]=service= )
local service
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local service="${service:-$app}"
local finalsystemdconf="/etc/systemd/system/$service.service"
if [ -e "$finalsystemdconf" ]; then
ynh_systemd_action --service_name=$service --action=stop
systemctl disable $service
ynh_secure_remove --file="$finalsystemdconf"
systemctl daemon-reload
fi
}
# Create a dedicated nginx config
#
# usage: ynh_add_nginx_config "list of others variables to replace"
#
# | arg: list - (Optional) list of others variables to replace separated by spaces. For example : 'path_2 port_2 ...'
#
# This will use a template in ../conf/nginx.conf
# __PATH__ by $path_url
# __DOMAIN__ by $domain
# __PORT__ by $port
# __NAME__ by $app
# __FINALPATH__ by $final_path
#
# And dynamic variables (from the last example) :
# __PATH_2__ by $path_2
# __PORT_2__ by $port_2
#
# Requires YunoHost version 2.7.2 or higher.
ynh_add_nginx_config () {
finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf"
local others_var=${1:-}
ynh_backup_if_checksum_is_different --file="$finalnginxconf"
sudo cp ../conf/nginx.conf "$finalnginxconf"
# To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable.
# Substitute in a nginx config file only if the variable is not empty
if test -n "${path_url:-}"; then
# path_url_slash_less is path_url, or a blank value if path_url is only '/'
local path_url_slash_less=${path_url%/}
ynh_replace_string --match_string="__PATH__/" --replace_string="$path_url_slash_less/" --target_file="$finalnginxconf"
ynh_replace_string --match_string="__PATH__" --replace_string="$path_url" --target_file="$finalnginxconf"
fi
if test -n "${domain:-}"; then
ynh_replace_string --match_string="__DOMAIN__" --replace_string="$domain" --target_file="$finalnginxconf"
fi
if test -n "${port:-}"; then
ynh_replace_string --match_string="__PORT__" --replace_string="$port" --target_file="$finalnginxconf"
fi
if test -n "${app:-}"; then
ynh_replace_string --match_string="__NAME__" --replace_string="$app" --target_file="$finalnginxconf"
fi
if test -n "${final_path:-}"; then
ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalnginxconf"
fi
# Replace all other variable given as arguments
for var_to_replace in $others_var
do
# ${var_to_replace^^} make the content of the variable on upper-cases
# ${!var_to_replace} get the content of the variable named $var_to_replace
ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalnginxconf"
done
if [ "${path_url:-}" != "/" ]
then
ynh_replace_string --match_string="^#sub_path_only" --replace_string="" --target_file="$finalnginxconf"
else
ynh_replace_string --match_string="^#root_path_only" --replace_string="" --target_file="$finalnginxconf"
fi
ynh_store_file_checksum --file="$finalnginxconf"
ynh_systemd_action --service_name=nginx --action=reload
}
# Remove the dedicated nginx config
#
# usage: ynh_remove_nginx_config
#
# Requires YunoHost version 2.7.2 or higher.
ynh_remove_nginx_config () {
ynh_secure_remove --file="/etc/nginx/conf.d/$domain.d/$app.conf"
ynh_systemd_action --service_name=nginx --action=reload
}
# Create a dedicated php-fpm config
#
# usage: ynh_add_fpm_config [--phpversion=7.X]
# | arg: -v, --phpversion - Version of php to use.
#
# Requires YunoHost version 2.7.2 or higher.
ynh_add_fpm_config () {
# Declare an array to define the options of this helper.
local legacy_args=v
declare -Ar args_array=( [v]=phpversion= )
local phpversion
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
# Configure PHP-FPM 7.0 by default
phpversion="${phpversion:-7.0}"
local fpm_config_dir="/etc/php/$phpversion/fpm"
local fpm_service="php${phpversion}-fpm"
# Configure PHP-FPM 5 on Debian Jessie
if [ "$(ynh_get_debian_release)" == "jessie" ]; then
fpm_config_dir="/etc/php5/fpm"
fpm_service="php5-fpm"
fi
ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir"
ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service"
finalphpconf="$fpm_config_dir/pool.d/$app.conf"
ynh_backup_if_checksum_is_different --file="$finalphpconf"
sudo cp ../conf/php-fpm.conf "$finalphpconf"
ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$finalphpconf"
ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalphpconf"
ynh_replace_string --match_string="__USER__" --replace_string="$app" --target_file="$finalphpconf"
ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$phpversion" --target_file="$finalphpconf"
sudo chown root: "$finalphpconf"
ynh_store_file_checksum --file="$finalphpconf"
if [ -e "../conf/php-fpm.ini" ]
then
echo "Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead." >&2
finalphpini="$fpm_config_dir/conf.d/20-$app.ini"
ynh_backup_if_checksum_is_different "$finalphpini"
sudo cp ../conf/php-fpm.ini "$finalphpini"
sudo chown root: "$finalphpini"
ynh_store_file_checksum "$finalphpini"
fi
ynh_systemd_action --service_name=$fpm_service --action=reload
}
# Remove the dedicated php-fpm config
#
# usage: ynh_remove_fpm_config
#
# Requires YunoHost version 2.7.2 or higher.
ynh_remove_fpm_config () {
local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service)
# Assume php version 7 if not set
if [ -z "$fpm_config_dir" ]; then
fpm_config_dir="/etc/php/7.0/fpm"
fpm_service="php7.0-fpm"
fi
ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf"
ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini" 2>&1
ynh_systemd_action --service_name=$fpm_service --action=reload
}
# Create a dedicated fail2ban config (jail and filter conf files)
#
# usage 1: ynh_add_fail2ban_config --logpath=log_file --failregex=filter [--max_retry=max_retry] [--ports=ports]
# | arg: -l, --logpath= - Log file to be checked by fail2ban
# | arg: -r, --failregex= - Failregex to be looked for by fail2ban
# | arg: -m, --max_retry= - Maximum number of retries allowed before banning IP address - default: 3
# | arg: -p, --ports= - Ports blocked for a banned IP address - default: http,https
#
# -----------------------------------------------------------------------------
#
# usage 2: ynh_add_fail2ban_config --use_template [--others_var="list of others variables to replace"]
# | arg: -t, --use_template - Use this helper in template mode
# | arg: -v, --others_var= - List of others variables to replace separeted by a space
# | for example : 'var_1 var_2 ...'
#
# This will use a template in ../conf/f2b_jail.conf and ../conf/f2b_filter.conf
# __APP__ by $app
#
# You can dynamically replace others variables by example :
# __VAR_1__ by $var_1
# __VAR_2__ by $var_2
#
# Generally your template will look like that by example (for synapse):
#
# f2b_jail.conf:
# [__APP__]
# enabled = true
# port = http,https
# filter = __APP__
# logpath = /var/log/__APP__/logfile.log
# maxretry = 3
#
# f2b_filter.conf:
# [INCLUDES]
# before = common.conf
# [Definition]
#
# # Part of regex definition (just used to make more easy to make the global regex)
# __synapse_start_line = .? \- synapse\..+ \-
#
# # Regex definition.
# failregex = ^%(__synapse_start_line)s INFO \- POST\-(\d+)\- <HOST> \- \d+ \- Received request\: POST /_matrix/client/r0/login\??<SKIPLINES>%(__synapse_start_line)s INFO \- POST\-\1\- Got login request with identifier: \{u'type': u'm.id.user', u'user'\: u'(.+?)'\}, medium\: None, address: None, user\: u'\5'<SKIPLINES>%(__synapse_start_line)s WARNING \- \- (Attempted to login as @\5\:.+ but they do not exist|Failed password login for user @\5\:.+)$
#
# ignoreregex =
#
# -----------------------------------------------------------------------------
#
# Note about the "failregex" option:
# regex to match the password failure messages in the logfile. The
# host must be matched by a group named "host". The tag "<HOST>" can
# be used for standard IP/hostname matching and is only an alias for
# (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
#
# You can find some more explainations about how to make a regex here :
# https://www.fail2ban.org/wiki/index.php/MANUAL_0_8#Filters
#
# Note that the logfile need to exist before to call this helper !!
#
# To validate your regex you can test with this command:
# fail2ban-regex /var/log/YOUR_LOG_FILE_PATH /etc/fail2ban/filter.d/YOUR_APP.conf
#
# Requires YunoHost version 3.?.? or higher.
ynh_add_fail2ban_config () {
# Declare an array to define the options of this helper.
local legacy_args=lrmptv
declare -Ar args_array=( [l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template [v]=others_var=)
local logpath
local failregex
local max_retry
local ports
local others_var
local use_template
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
use_template="${use_template:-0}"
max_retry=${max_retry:-3}
ports=${ports:-http,https}
finalfail2banjailconf="/etc/fail2ban/jail.d/$app.conf"
finalfail2banfilterconf="/etc/fail2ban/filter.d/$app.conf"
ynh_backup_if_checksum_is_different "$finalfail2banjailconf"
ynh_backup_if_checksum_is_different "$finalfail2banfilterconf"
if [ $use_template -eq 1 ]
then
# Usage 2, templates
cp ../conf/f2b_jail.conf $finalfail2banjailconf
cp ../conf/f2b_filter.conf $finalfail2banfilterconf
if [ -n "${app:-}" ]
then
ynh_replace_string "__APP__" "$app" "$finalfail2banjailconf"
ynh_replace_string "__APP__" "$app" "$finalfail2banfilterconf"
fi
# Replace all other variable given as arguments
for var_to_replace in ${others_var:-}; do
# ${var_to_replace^^} make the content of the variable on upper-cases
# ${!var_to_replace} get the content of the variable named $var_to_replace
ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalfail2banjailconf"
ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalfail2banfilterconf"
done
else
# Usage 1, no template. Build a config file from scratch.
test -n "$logpath" || ynh_die "ynh_add_fail2ban_config expects a logfile path as first argument and received nothing."
test -n "$failregex" || ynh_die "ynh_add_fail2ban_config expects a failure regex as second argument and received nothing."
tee $finalfail2banjailconf <<EOF
[$app]
enabled = true
port = $ports
filter = $app
logpath = $logpath
maxretry = $max_retry
EOF
tee $finalfail2banfilterconf <<EOF
[INCLUDES]
before = common.conf
[Definition]
failregex = $failregex
ignoreregex =
EOF
fi
# Common to usage 1 and 2.
ynh_store_file_checksum "$finalfail2banjailconf"
ynh_store_file_checksum "$finalfail2banfilterconf"
ynh_systemd_action --service_name=fail2ban --action=reload
local fail2ban_error="$(journalctl -u fail2ban | tail -n50 | grep "WARNING.*$app.*")"
if [[ -n "$fail2ban_error" ]]; then
ynh_print_err --message="Fail2ban failed to load the jail for $app"
ynh_print_warn --message="${fail2ban_error#*WARNING}"
fi
}
# Remove the dedicated fail2ban config (jail and filter conf files)
#
# usage: ynh_remove_fail2ban_config
#
# Requires YunoHost version 3.?.? or higher.
ynh_remove_fail2ban_config () {
ynh_secure_remove "/etc/fail2ban/jail.d/$app.conf"
ynh_secure_remove "/etc/fail2ban/filter.d/$app.conf"
ynh_systemd_action --service_name=fail2ban --action=reload
}

View file

@ -1,7 +1,5 @@
#!/bin/bash
source /usr/share/yunohost/helpers.d/getopts
CAN_BIND=${CAN_BIND:-1}
# Add a file or a directory to the list of paths to backup
@ -282,26 +280,6 @@ ynh_bind_or_cp() {
ynh_backup "$1" "$2" 1
}
# Create a directory under /tmp
#
# [internal]
#
# Deprecated helper
#
# usage: ynh_mkdir_tmp
# | ret: the created directory path
ynh_mkdir_tmp() {
ynh_print_warn --message="The helper ynh_mkdir_tmp is deprecated."
ynh_print_warn --message="You should use 'mktemp -d' instead and manage permissions \
properly with chmod/chown."
local TMP_DIR=$(mktemp -d)
# Give rights to other users could be a security risk.
# But for retrocompatibility we need it. (This helpers is deprecated)
chmod 755 $TMP_DIR
echo $TMP_DIR
}
# Calculate and store a file checksum into the app settings
#
# $app should be defined when calling this helper
@ -388,43 +366,83 @@ ynh_delete_file_checksum () {
ynh_app_setting_delete --app=$app --key=$checksum_setting_name
}
# Remove a file or a directory securely
# Make a backup in case of failed upgrade
#
# usage: ynh_secure_remove --file=path_to_remove
# | arg: -f, --file - File or directory to remove
# usage:
# ynh_backup_before_upgrade
# ynh_clean_setup () {
# ynh_restore_upgradebackup
# }
# ynh_abort_if_errors
#
# Requires YunoHost version 2.6.4 or higher.
ynh_secure_remove () {
# Declare an array to define the options of this helper.
local legacy_args=f
declare -Ar args_array=( [f]=file= )
local file
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local forbidden_path=" \
/var/www \
/home/yunohost.app"
if [ $# -ge 2 ]
# Requires YunoHost version 2.7.2 or higher.
ynh_backup_before_upgrade () {
if [ ! -e "/etc/yunohost/apps/$app/scripts/backup" ]
then
ynh_print_warn --message="/!\ Packager ! You provided more than one argument to ynh_secure_remove but it will be ignored... Use this helper with one argument at time."
ynh_print_warn --message="This app doesn't have any backup script."
return
fi
backup_number=1
local old_backup_number=2
local app_bck=${app//_/-} # Replace all '_' by '-'
NO_BACKUP_UPGRADE=${NO_BACKUP_UPGRADE:-0}
if [ "$NO_BACKUP_UPGRADE" -eq 0 ]
then
# Check if a backup already exists with the prefix 1
if sudo yunohost backup list | grep -q $app_bck-pre-upgrade1
then
# Prefix becomes 2 to preserve the previous backup
backup_number=2
old_backup_number=1
fi
if [[ "$forbidden_path" =~ "$file" \
# Match all paths or subpaths in $forbidden_path
|| "$file" =~ ^/[[:alnum:]]+$ \
# Match all first level paths from / (Like /var, /root, etc...)
|| "${file:${#file}-1}" = "/" ]]
# Match if the path finishes by /. Because it seems there is an empty variable
# Create backup
sudo BACKUP_CORE_ONLY=1 yunohost backup create --apps $app --name $app_bck-pre-upgrade$backup_number --debug
if [ "$?" -eq 0 ]
then
ynh_print_warn --message="Avoid deleting $file."
else
if [ -e "$file" ]
# If the backup succeeded, remove the previous backup
if sudo yunohost backup list | grep -q $app_bck-pre-upgrade$old_backup_number
then
sudo rm -R "$file"
else
ynh_print_info --message="$file wasn't deleted because it doesn't exist."
# Remove the previous backup only if it exists
sudo yunohost backup delete $app_bck-pre-upgrade$old_backup_number > /dev/null
fi
else
ynh_die --message="Backup failed, the upgrade process was aborted."
fi
else
ynh_print_warn --message="\$NO_BACKUP_UPGRADE is set, backup will be avoided. Be careful, this upgrade is going to be operated without a security backup"
fi
}
# Restore a previous backup if the upgrade process failed
#
# usage:
# ynh_backup_before_upgrade
# ynh_clean_setup () {
# ynh_restore_upgradebackup
# }
# ynh_abort_if_errors
#
# Requires YunoHost version 2.7.2 or higher.
ynh_restore_upgradebackup () {
ynh_print_err --message="Upgrade failed."
local app_bck=${app//_/-} # Replace all '_' by '-'
NO_BACKUP_UPGRADE=${NO_BACKUP_UPGRADE:-0}
if [ "$NO_BACKUP_UPGRADE" -eq 0 ]
then
# Check if an existing backup can be found before removing and restoring the application.
if sudo yunohost backup list | grep -q $app_bck-pre-upgrade$backup_number
then
# Remove the application then restore it
sudo yunohost app remove $app
# Restore the backup
sudo yunohost backup restore $app_bck-pre-upgrade$backup_number --apps $app --force --debug
ynh_die --message="The app was restored to the way it was before the failed upgrade."
fi
else
ynh_print_warn --message="\$NO_BACKUP_UPGRADE is set, that means there's no backup to restore. You have to fix this upgrade by yourself !"
fi
}

View file

@ -1,67 +0,0 @@
#!/bin/bash
# Debugger for app packagers
#
# usage: ynh_debug [--message=message] [--trace=1/0]
# | arg: -m, --message= - The text to print
# | arg: -t, --trace= - Turn on or off the trace of the script. Usefull to trace nonly a small part of a script.
#
# Requires YunoHost version 3.?.? or higher.
ynh_debug () {
# Disable set xtrace for the helper itself, to not pollute the debug log
set +x
# Declare an array to define the options of this helper.
local legacy_args=mt
declare -Ar args_array=( [m]=message= [t]=trace= )
local message
local trace
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
# Redisable xtrace, ynh_handle_getopts_args set it back
set +x
message=${message:-}
trace=${trace:-}
if [ -n "$message" ]
then
ynh_print_log "\e[34m\e[1m[DEBUG]\e[0m ${message}" >&2
fi
if [ "$trace" == "1" ]
then
ynh_debug --message="Enable debugging"
set +x
# Get the current file descriptor of xtrace
old_bash_xtracefd=$BASH_XTRACEFD
# Add the current file name and the line number of any command currently running while tracing.
PS4='$(basename ${BASH_SOURCE[0]})-L${LINENO}: '
# Force xtrace to stderr
BASH_XTRACEFD=2
# Force stdout to stderr
exec 1>&2
fi
if [ "$trace" == "0" ]
then
ynh_debug --message="Disable debugging"
set +x
# Put xtrace back to its original fild descriptor
BASH_XTRACEFD=$old_bash_xtracefd
# Restore stdout
exec 1>&1
fi
# Renable set xtrace
set -x
}
# Execute a command and print the result as debug
#
# usage: ynh_debug_exec command to execute
# usage: ynh_debug_exec "command to execute | following command"
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
#
# | arg: command - command to execute
#
# Requires YunoHost version 3.?.? or higher.
ynh_debug_exec () {
ynh_debug --message="$(eval $@)"
}

151
data/helpers.d/fail2ban Normal file
View file

@ -0,0 +1,151 @@
#!/bin/bash
# Create a dedicated fail2ban config (jail and filter conf files)
#
# usage 1: ynh_add_fail2ban_config --logpath=log_file --failregex=filter [--max_retry=max_retry] [--ports=ports]
# | arg: -l, --logpath= - Log file to be checked by fail2ban
# | arg: -r, --failregex= - Failregex to be looked for by fail2ban
# | arg: -m, --max_retry= - Maximum number of retries allowed before banning IP address - default: 3
# | arg: -p, --ports= - Ports blocked for a banned IP address - default: http,https
#
# -----------------------------------------------------------------------------
#
# usage 2: ynh_add_fail2ban_config --use_template [--others_var="list of others variables to replace"]
# | arg: -t, --use_template - Use this helper in template mode
# | arg: -v, --others_var= - List of others variables to replace separeted by a space
# | for example : 'var_1 var_2 ...'
#
# This will use a template in ../conf/f2b_jail.conf and ../conf/f2b_filter.conf
# __APP__ by $app
#
# You can dynamically replace others variables by example :
# __VAR_1__ by $var_1
# __VAR_2__ by $var_2
#
# Generally your template will look like that by example (for synapse):
#
# f2b_jail.conf:
# [__APP__]
# enabled = true
# port = http,https
# filter = __APP__
# logpath = /var/log/__APP__/logfile.log
# maxretry = 3
#
# f2b_filter.conf:
# [INCLUDES]
# before = common.conf
# [Definition]
#
# # Part of regex definition (just used to make more easy to make the global regex)
# __synapse_start_line = .? \- synapse\..+ \-
#
# # Regex definition.
# failregex = ^%(__synapse_start_line)s INFO \- POST\-(\d+)\- <HOST> \- \d+ \- Received request\: POST /_matrix/client/r0/login\??<SKIPLINES>%(__synapse_start_line)s INFO \- POST\-\1\- Got login request with identifier: \{u'type': u'm.id.user', u'user'\: u'(.+?)'\}, medium\: None, address: None, user\: u'\5'<SKIPLINES>%(__synapse_start_line)s WARNING \- \- (Attempted to login as @\5\:.+ but they do not exist|Failed password login for user @\5\:.+)$
#
# ignoreregex =
#
# -----------------------------------------------------------------------------
#
# Note about the "failregex" option:
# regex to match the password failure messages in the logfile. The
# host must be matched by a group named "host". The tag "<HOST>" can
# be used for standard IP/hostname matching and is only an alias for
# (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
#
# You can find some more explainations about how to make a regex here :
# https://www.fail2ban.org/wiki/index.php/MANUAL_0_8#Filters
#
# Note that the logfile need to exist before to call this helper !!
#
# To validate your regex you can test with this command:
# fail2ban-regex /var/log/YOUR_LOG_FILE_PATH /etc/fail2ban/filter.d/YOUR_APP.conf
#
# Requires YunoHost version 3.?.? or higher.
ynh_add_fail2ban_config () {
# Declare an array to define the options of this helper.
local legacy_args=lrmptv
declare -Ar args_array=( [l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template [v]=others_var=)
local logpath
local failregex
local max_retry
local ports
local others_var
local use_template
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
use_template="${use_template:-0}"
max_retry=${max_retry:-3}
ports=${ports:-http,https}
finalfail2banjailconf="/etc/fail2ban/jail.d/$app.conf"
finalfail2banfilterconf="/etc/fail2ban/filter.d/$app.conf"
ynh_backup_if_checksum_is_different "$finalfail2banjailconf"
ynh_backup_if_checksum_is_different "$finalfail2banfilterconf"
if [ $use_template -eq 1 ]
then
# Usage 2, templates
cp ../conf/f2b_jail.conf $finalfail2banjailconf
cp ../conf/f2b_filter.conf $finalfail2banfilterconf
if [ -n "${app:-}" ]
then
ynh_replace_string "__APP__" "$app" "$finalfail2banjailconf"
ynh_replace_string "__APP__" "$app" "$finalfail2banfilterconf"
fi
# Replace all other variable given as arguments
for var_to_replace in ${others_var:-}; do
# ${var_to_replace^^} make the content of the variable on upper-cases
# ${!var_to_replace} get the content of the variable named $var_to_replace
ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalfail2banjailconf"
ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalfail2banfilterconf"
done
else
# Usage 1, no template. Build a config file from scratch.
test -n "$logpath" || ynh_die "ynh_add_fail2ban_config expects a logfile path as first argument and received nothing."
test -n "$failregex" || ynh_die "ynh_add_fail2ban_config expects a failure regex as second argument and received nothing."
tee $finalfail2banjailconf <<EOF
[$app]
enabled = true
port = $ports
filter = $app
logpath = $logpath
maxretry = $max_retry
EOF
tee $finalfail2banfilterconf <<EOF
[INCLUDES]
before = common.conf
[Definition]
failregex = $failregex
ignoreregex =
EOF
fi
# Common to usage 1 and 2.
ynh_store_file_checksum "$finalfail2banjailconf"
ynh_store_file_checksum "$finalfail2banfilterconf"
ynh_systemd_action --service_name=fail2ban --action=reload
local fail2ban_error="$(journalctl -u fail2ban | tail -n50 | grep "WARNING.*$app.*")"
if [[ -n "$fail2ban_error" ]]; then
ynh_print_err --message="Fail2ban failed to load the jail for $app"
ynh_print_warn --message="${fail2ban_error#*WARNING}"
fi
}
# Remove the dedicated fail2ban config (jail and filter conf files)
#
# usage: ynh_remove_fail2ban_config
#
# Requires YunoHost version 3.?.? or higher.
ynh_remove_fail2ban_config () {
ynh_secure_remove "/etc/fail2ban/jail.d/$app.conf"
ynh_secure_remove "/etc/fail2ban/filter.d/$app.conf"
ynh_systemd_action --service_name=fail2ban --action=reload
}

View file

@ -1,76 +0,0 @@
#!/bin/bash
# Validate an IP address
#
# usage: ynh_validate_ip --family=family --ip_address=ip_address
# | ret: 0 for valid ip addresses, 1 otherwise
#
# example: ynh_validate_ip 4 111.222.333.444
#
# Requires YunoHost version 2.2.4 or higher.
ynh_validate_ip()
{
# http://stackoverflow.com/questions/319279/how-to-validate-ip-address-in-python#319298
# Declare an array to define the options of this helper.
local legacy_args=fi
declare -Ar args_array=( [f]=family= [i]=ip_address= )
local family
local ip_address
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
[ "$family" == "4" ] || [ "$family" == "6" ] || return 1
python /dev/stdin << EOF
import socket
import sys
family = { "4" : socket.AF_INET, "6" : socket.AF_INET6 }
try:
socket.inet_pton(family["$family"], "$ip_address")
except socket.error:
sys.exit(1)
sys.exit(0)
EOF
}
# Validate an IPv4 address
#
# example: ynh_validate_ip4 111.222.333.444
#
# usage: ynh_validate_ip4 --ip_address=ip_address
# | ret: 0 for valid ipv4 addresses, 1 otherwise
#
# Requires YunoHost version 2.2.4 or higher.
ynh_validate_ip4()
{
# Declare an array to define the options of this helper.
local legacy_args=i
declare -Ar args_array=( [i]=ip_address= )
local ip_address
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
ynh_validate_ip 4 $ip_address
}
# Validate an IPv6 address
#
# example: ynh_validate_ip6 2000:dead:beef::1
#
# usage: ynh_validate_ip6 --ip_address=ip_address
# | ret: 0 for valid ipv6 addresses, 1 otherwise
#
# Requires YunoHost version 2.2.4 or higher.
ynh_validate_ip6()
{
# Declare an array to define the options of this helper.
local legacy_args=i
declare -Ar args_array=( [i]=ip_address= )
local ip_address
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
ynh_validate_ip 6 $ip_address
}

View file

@ -277,3 +277,69 @@ ynh_script_progression () {
ynh_print_info "[$progression_bar] > ${message}${print_exec_time}"
}
# Debugger for app packagers
#
# usage: ynh_debug [--message=message] [--trace=1/0]
# | arg: -m, --message= - The text to print
# | arg: -t, --trace= - Turn on or off the trace of the script. Usefull to trace nonly a small part of a script.
#
# Requires YunoHost version 3.?.? or higher.
ynh_debug () {
# Disable set xtrace for the helper itself, to not pollute the debug log
set +x
# Declare an array to define the options of this helper.
local legacy_args=mt
declare -Ar args_array=( [m]=message= [t]=trace= )
local message
local trace
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
# Redisable xtrace, ynh_handle_getopts_args set it back
set +x
message=${message:-}
trace=${trace:-}
if [ -n "$message" ]
then
ynh_print_log "\e[34m\e[1m[DEBUG]\e[0m ${message}" >&2
fi
if [ "$trace" == "1" ]
then
ynh_debug --message="Enable debugging"
set +x
# Get the current file descriptor of xtrace
old_bash_xtracefd=$BASH_XTRACEFD
# Add the current file name and the line number of any command currently running while tracing.
PS4='$(basename ${BASH_SOURCE[0]})-L${LINENO}: '
# Force xtrace to stderr
BASH_XTRACEFD=2
# Force stdout to stderr
exec 1>&2
fi
if [ "$trace" == "0" ]
then
ynh_debug --message="Disable debugging"
set +x
# Put xtrace back to its original fild descriptor
BASH_XTRACEFD=$old_bash_xtracefd
# Restore stdout
exec 1>&1
fi
# Renable set xtrace
set -x
}
# Execute a command and print the result as debug
#
# usage: ynh_debug_exec command to execute
# usage: ynh_debug_exec "command to execute | following command"
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
#
# | arg: command - command to execute
#
# Requires YunoHost version 3.?.? or higher.
ynh_debug_exec () {
ynh_debug --message="$(eval $@)"
}

103
data/helpers.d/logrotate Normal file
View file

@ -0,0 +1,103 @@
#!/bin/bash
# Use logrotate to manage the logfile
#
# usage: ynh_use_logrotate [--logfile=/log/file] [--nonappend] [--specific_user=user/group]
# | arg: -l, --logfile - absolute path of logfile
# | arg: -n, --nonappend - (optional) Replace the config file instead of appending this new config.
# | arg: -u, --specific_user : run logrotate as the specified user and group. If not specified logrotate is runned as root.
#
# If no --logfile is provided, /var/log/${app} will be used as default.
# logfile can be just a directory, or a full path to a logfile :
# /parentdir/logdir
# /parentdir/logdir/logfile.log
#
# It's possible to use this helper multiple times, each config will be added to
# the same logrotate config file. Unless you use the option --non-append
#
# Requires YunoHost version 2.6.4 or higher.
ynh_use_logrotate () {
# Declare an array to define the options of this helper.
local legacy_args=lnuya
declare -Ar args_array=( [l]=logfile= [n]=nonappend [u]=specific_user= [y]=non [a]=append )
# [y]=non [a]=append are only for legacy purpose, to not fail on the old option '--non-append'
local logfile
local nonappend
local specific_user
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local logfile="${logfile:-}"
local nonappend="${nonappend:-0}"
local specific_user="${specific_user:-}"
# LEGACY CODE - PRE GETOPTS
if [ $# -gt 0 ] && [ "$1" == "--non-append" ]; then
nonappend=1
# Destroy this argument for the next command.
shift
elif [ $# -gt 1 ] && [ "$2" == "--non-append" ]; then
nonappend=1
fi
if [ $# -gt 0 ] && [ "$(echo ${1:0:1})" != "-" ]; then
if [ "$(echo ${1##*.})" == "log" ]; then # Keep only the extension to check if it's a logfile
local logfile=$1 # In this case, focus logrotate on the logfile
else
local logfile=$1/*.log # Else, uses the directory and all logfile into it.
fi
fi
# LEGACY CODE
local customtee="tee -a"
if [ "$nonappend" -eq 1 ]; then
customtee="tee"
fi
if [ -n "$logfile" ]
then
if [ "$(echo ${logfile##*.})" != "log" ]; then # Keep only the extension to check if it's a logfile
local logfile="$logfile/*.log" # Else, uses the directory and all logfile into it.
fi
else
logfile="/var/log/${app}/*.log" # Without argument, use a defaut directory in /var/log
fi
local su_directive=""
if [[ -n $specific_user ]]; then
su_directive=" # Run logorotate as specific user - group
su ${specific_user%/*} ${specific_user#*/}"
fi
cat > ./${app}-logrotate << EOF # Build a config file for logrotate
$logfile {
# Rotate if the logfile exceeds 100Mo
size 100M
# Keep 12 old log maximum
rotate 12
# Compress the logs with gzip
compress
# Compress the log at the next cycle. So keep always 2 non compressed logs
delaycompress
# Copy and truncate the log to allow to continue write on it. Instead of move the log.
copytruncate
# Do not do an error if the log is missing
missingok
# Not rotate if the log is empty
notifempty
# Keep old logs in the same dir
noolddir
$su_directive
}
EOF
sudo mkdir -p $(dirname "$logfile") # Create the log directory, if not exist
cat ${app}-logrotate | sudo $customtee /etc/logrotate.d/$app > /dev/null # Append this config to the existing config file, or replace the whole config file (depending on $customtee)
}
# Remove the app's logrotate config.
#
# usage: ynh_remove_logrotate
#
# Requires YunoHost version 2.6.4 or higher.
ynh_remove_logrotate () {
if [ -e "/etc/logrotate.d/$app" ]; then
sudo rm "/etc/logrotate.d/$app"
fi
}

View file

@ -237,24 +237,3 @@ ynh_mysql_remove_db () {
fi
}
# Sanitize a string intended to be the name of a database
# (More specifically : replace - and . by _)
#
# example: dbname=$(ynh_sanitize_dbid $app)
#
# usage: ynh_sanitize_dbid --db_name=name
# | arg: -n, --db_name - name to correct/sanitize
# | ret: the corrected name
#
# Requires YunoHost version 2.2.4 or higher.
ynh_sanitize_dbid () {
# Declare an array to define the options of this helper.
local legacy_args=n
declare -Ar args_array=( [n]=db_name= )
local db_name
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
# We should avoid having - and . in the name of databases. They are replaced by _
echo ${db_name//[-.]/_}
}

View file

@ -1,39 +1,5 @@
#!/bin/bash
# Normalize the url path syntax
#
# Handle the slash at the beginning of path and its absence at ending
# Return a normalized url path
#
# examples:
# url_path=$(ynh_normalize_url_path $url_path)
# ynh_normalize_url_path example # -> /example
# ynh_normalize_url_path /example # -> /example
# ynh_normalize_url_path /example/ # -> /example
# ynh_normalize_url_path / # -> /
#
# usage: ynh_normalize_url_path --path_url=path_to_normalize
# | arg: -p, --path_url - URL path to normalize before using it
#
# Requires YunoHost version 2.6.4 or higher.
ynh_normalize_url_path () {
# Declare an array to define the options of this helper.
local legacy_args=p
declare -Ar args_array=( [p]=path_url= )
local path_url
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
test -n "$path_url" || ynh_die --message="ynh_normalize_url_path expect a URL path as first argument and received nothing."
if [ "${path_url:0:1}" != "/" ]; then # If the first character is not a /
path_url="/$path_url" # Add / at begin of path variable
fi
if [ "${path_url:${#path_url}-1}" == "/" ] && [ ${#path_url} -gt 1 ]; then # If the last character is a / and that not the only character.
path_url="${path_url:0:${#path_url}-1}" # Delete the last character
fi
echo $path_url
}
# Find a free port and return it
#
# example: port=$(ynh_find_port --port=8080)
@ -58,46 +24,77 @@ ynh_find_port () {
echo $port
}
# Check availability of a web path
# Validate an IP address
#
# example: ynh_webpath_available --domain=some.domain.tld --path_url=/coffee
# usage: ynh_validate_ip --family=family --ip_address=ip_address
# | ret: 0 for valid ip addresses, 1 otherwise
#
# usage: ynh_webpath_available --domain=domain --path_url=path
# | arg: -d, --domain - the domain/host of the url
# | arg: -p, --path_url - the web path to check the availability of
# example: ynh_validate_ip 4 111.222.333.444
#
# Requires YunoHost version 2.6.4 or higher.
ynh_webpath_available () {
# Requires YunoHost version 2.2.4 or higher.
ynh_validate_ip()
{
# http://stackoverflow.com/questions/319279/how-to-validate-ip-address-in-python#319298
# Declare an array to define the options of this helper.
local legacy_args=dp
declare -Ar args_array=( [d]=domain= [p]=path_url= )
local domain
local path_url
local legacy_args=fi
declare -Ar args_array=( [f]=family= [i]=ip_address= )
local family
local ip_address
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
sudo yunohost domain url-available $domain $path_url
[ "$family" == "4" ] || [ "$family" == "6" ] || return 1
python /dev/stdin << EOF
import socket
import sys
family = { "4" : socket.AF_INET, "6" : socket.AF_INET6 }
try:
socket.inet_pton(family["$family"], "$ip_address")
except socket.error:
sys.exit(1)
sys.exit(0)
EOF
}
# Register/book a web path for an app
# Validate an IPv4 address
#
# example: ynh_webpath_register --app=wordpress --domain=some.domain.tld --path_url=/coffee
# example: ynh_validate_ip4 111.222.333.444
#
# usage: ynh_webpath_register --app=app --domain=domain --path_url=path
# | arg: -a, --app - the app for which the domain should be registered
# | arg: -d, --domain - the domain/host of the web path
# | arg: -p, --path_url - the web path to be registered
# usage: ynh_validate_ip4 --ip_address=ip_address
# | ret: 0 for valid ipv4 addresses, 1 otherwise
#
# Requires YunoHost version 2.6.4 or higher.
ynh_webpath_register () {
# Requires YunoHost version 2.2.4 or higher.
ynh_validate_ip4()
{
# Declare an array to define the options of this helper.
local legacy_args=adp
declare -Ar args_array=( [a]=app= [d]=domain= [p]=path_url= )
local app
local domain
local path_url
local legacy_args=i
declare -Ar args_array=( [i]=ip_address= )
local ip_address
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
sudo yunohost app register-url $app $domain $path_url
ynh_validate_ip 4 $ip_address
}
# Validate an IPv6 address
#
# example: ynh_validate_ip6 2000:dead:beef::1
#
# usage: ynh_validate_ip6 --ip_address=ip_address
# | ret: 0 for valid ipv6 addresses, 1 otherwise
#
# Requires YunoHost version 2.2.4 or higher.
ynh_validate_ip6()
{
# Declare an array to define the options of this helper.
local legacy_args=i
declare -Ar args_array=( [i]=ip_address= )
local ip_address
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
ynh_validate_ip 6 $ip_address
}

76
data/helpers.d/nginx Normal file
View file

@ -0,0 +1,76 @@
#!/bin/bash
# Create a dedicated nginx config
#
# usage: ynh_add_nginx_config "list of others variables to replace"
#
# | arg: list - (Optional) list of others variables to replace separated by spaces. For example : 'path_2 port_2 ...'
#
# This will use a template in ../conf/nginx.conf
# __PATH__ by $path_url
# __DOMAIN__ by $domain
# __PORT__ by $port
# __NAME__ by $app
# __FINALPATH__ by $final_path
#
# And dynamic variables (from the last example) :
# __PATH_2__ by $path_2
# __PORT_2__ by $port_2
#
# Requires YunoHost version 2.7.2 or higher.
ynh_add_nginx_config () {
finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf"
local others_var=${1:-}
ynh_backup_if_checksum_is_different --file="$finalnginxconf"
sudo cp ../conf/nginx.conf "$finalnginxconf"
# To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable.
# Substitute in a nginx config file only if the variable is not empty
if test -n "${path_url:-}"; then
# path_url_slash_less is path_url, or a blank value if path_url is only '/'
local path_url_slash_less=${path_url%/}
ynh_replace_string --match_string="__PATH__/" --replace_string="$path_url_slash_less/" --target_file="$finalnginxconf"
ynh_replace_string --match_string="__PATH__" --replace_string="$path_url" --target_file="$finalnginxconf"
fi
if test -n "${domain:-}"; then
ynh_replace_string --match_string="__DOMAIN__" --replace_string="$domain" --target_file="$finalnginxconf"
fi
if test -n "${port:-}"; then
ynh_replace_string --match_string="__PORT__" --replace_string="$port" --target_file="$finalnginxconf"
fi
if test -n "${app:-}"; then
ynh_replace_string --match_string="__NAME__" --replace_string="$app" --target_file="$finalnginxconf"
fi
if test -n "${final_path:-}"; then
ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalnginxconf"
fi
# Replace all other variable given as arguments
for var_to_replace in $others_var
do
# ${var_to_replace^^} make the content of the variable on upper-cases
# ${!var_to_replace} get the content of the variable named $var_to_replace
ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalnginxconf"
done
if [ "${path_url:-}" != "/" ]
then
ynh_replace_string --match_string="^#sub_path_only" --replace_string="" --target_file="$finalnginxconf"
else
ynh_replace_string --match_string="^#root_path_only" --replace_string="" --target_file="$finalnginxconf"
fi
ynh_store_file_checksum --file="$finalnginxconf"
ynh_systemd_action --service_name=nginx --action=reload
}
# Remove the dedicated nginx config
#
# usage: ynh_remove_nginx_config
#
# Requires YunoHost version 2.7.2 or higher.
ynh_remove_nginx_config () {
ynh_secure_remove --file="/etc/nginx/conf.d/$domain.d/$app.conf"
ynh_systemd_action --service_name=nginx --action=reload
}

67
data/helpers.d/php Normal file
View file

@ -0,0 +1,67 @@
#!/bin/bash
# Create a dedicated php-fpm config
#
# usage: ynh_add_fpm_config [--phpversion=7.X]
# | arg: -v, --phpversion - Version of php to use.
#
# Requires YunoHost version 2.7.2 or higher.
ynh_add_fpm_config () {
# Declare an array to define the options of this helper.
local legacy_args=v
declare -Ar args_array=( [v]=phpversion= )
local phpversion
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
# Configure PHP-FPM 7.0 by default
phpversion="${phpversion:-7.0}"
local fpm_config_dir="/etc/php/$phpversion/fpm"
local fpm_service="php${phpversion}-fpm"
# Configure PHP-FPM 5 on Debian Jessie
if [ "$(ynh_get_debian_release)" == "jessie" ]; then
fpm_config_dir="/etc/php5/fpm"
fpm_service="php5-fpm"
fi
ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir"
ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service"
finalphpconf="$fpm_config_dir/pool.d/$app.conf"
ynh_backup_if_checksum_is_different --file="$finalphpconf"
sudo cp ../conf/php-fpm.conf "$finalphpconf"
ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$finalphpconf"
ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalphpconf"
ynh_replace_string --match_string="__USER__" --replace_string="$app" --target_file="$finalphpconf"
ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$phpversion" --target_file="$finalphpconf"
sudo chown root: "$finalphpconf"
ynh_store_file_checksum --file="$finalphpconf"
if [ -e "../conf/php-fpm.ini" ]
then
echo "Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead." >&2
finalphpini="$fpm_config_dir/conf.d/20-$app.ini"
ynh_backup_if_checksum_is_different "$finalphpini"
sudo cp ../conf/php-fpm.ini "$finalphpini"
sudo chown root: "$finalphpini"
ynh_store_file_checksum "$finalphpini"
fi
ynh_systemd_action --service_name=$fpm_service --action=reload
}
# Remove the dedicated php-fpm config
#
# usage: ynh_remove_fpm_config
#
# Requires YunoHost version 2.7.2 or higher.
ynh_remove_fpm_config () {
local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service)
# Assume php version 7 if not set
if [ -z "$fpm_config_dir" ]; then
fpm_config_dir="/etc/php/7.0/fpm"
fpm_service="php7.0-fpm"
fi
ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf"
ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini" 2>&1
ynh_systemd_action --service_name=$fpm_service --action=reload
}

View file

@ -91,3 +91,47 @@ else:
yaml.safe_dump(settings, f, default_flow_style=False)
EOF
}
# Check availability of a web path
#
# example: ynh_webpath_available --domain=some.domain.tld --path_url=/coffee
#
# usage: ynh_webpath_available --domain=domain --path_url=path
# | arg: -d, --domain - the domain/host of the url
# | arg: -p, --path_url - the web path to check the availability of
#
# Requires YunoHost version 2.6.4 or higher.
ynh_webpath_available () {
# Declare an array to define the options of this helper.
local legacy_args=dp
declare -Ar args_array=( [d]=domain= [p]=path_url= )
local domain
local path_url
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
sudo yunohost domain url-available $domain $path_url
}
# Register/book a web path for an app
#
# example: ynh_webpath_register --app=wordpress --domain=some.domain.tld --path_url=/coffee
#
# usage: ynh_webpath_register --app=app --domain=domain --path_url=path
# | arg: -a, --app - the app for which the domain should be registered
# | arg: -d, --domain - the domain/host of the web path
# | arg: -p, --path_url - the web path to be registered
#
# Requires YunoHost version 2.6.4 or higher.
ynh_webpath_register () {
# Declare an array to define the options of this helper.
local legacy_args=adp
declare -Ar args_array=( [a]=app= [d]=domain= [p]=path_url= )
local app
local domain
local path_url
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
sudo yunohost app register-url $app $domain $path_url
}

View file

@ -83,3 +83,59 @@ ynh_replace_special_string () {
ynh_replace_string --match_string="$match_string" --replace_string="$replace_string" --target_file="$target_file"
}
# Sanitize a string intended to be the name of a database
# (More specifically : replace - and . by _)
#
# example: dbname=$(ynh_sanitize_dbid $app)
#
# usage: ynh_sanitize_dbid --db_name=name
# | arg: -n, --db_name - name to correct/sanitize
# | ret: the corrected name
#
# Requires YunoHost version 2.2.4 or higher.
ynh_sanitize_dbid () {
# Declare an array to define the options of this helper.
local legacy_args=n
declare -Ar args_array=( [n]=db_name= )
local db_name
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
# We should avoid having - and . in the name of databases. They are replaced by _
echo ${db_name//[-.]/_}
}
# Normalize the url path syntax
#
# Handle the slash at the beginning of path and its absence at ending
# Return a normalized url path
#
# examples:
# url_path=$(ynh_normalize_url_path $url_path)
# ynh_normalize_url_path example # -> /example
# ynh_normalize_url_path /example # -> /example
# ynh_normalize_url_path /example/ # -> /example
# ynh_normalize_url_path / # -> /
#
# usage: ynh_normalize_url_path --path_url=path_to_normalize
# | arg: -p, --path_url - URL path to normalize before using it
#
# Requires YunoHost version 2.6.4 or higher.
ynh_normalize_url_path () {
# Declare an array to define the options of this helper.
local legacy_args=p
declare -Ar args_array=( [p]=path_url= )
local path_url
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
test -n "$path_url" || ynh_die --message="ynh_normalize_url_path expect a URL path as first argument and received nothing."
if [ "${path_url:0:1}" != "/" ]; then # If the first character is not a /
path_url="/$path_url" # Add / at begin of path variable
fi
if [ "${path_url:${#path_url}-1}" == "/" ] && [ ${#path_url} -gt 1 ]; then # If the last character is a / and that not the only character.
path_url="${path_url:0:${#path_url}-1}" # Delete the last character
fi
echo $path_url
}

View file

@ -1,285 +0,0 @@
#!/bin/bash
# Manage a fail of the script
#
# [internal]
#
# usage:
# ynh_exit_properly is used only by the helper ynh_abort_if_errors.
# You should not use it directly.
# Instead, add to your script:
# ynh_clean_setup () {
# instructions...
# }
#
# This function provide a way to clean some residual of installation that not managed by remove script.
#
# It prints a warning to inform that the script was failed, and execute the ynh_clean_setup function if used in the app script
#
# Requires YunoHost version 2.6.4 or higher.
ynh_exit_properly () {
local exit_code=$?
if [ "$exit_code" -eq 0 ]; then
exit 0 # Exit without error if the script ended correctly
fi
trap '' EXIT # Ignore new exit signals
set +eu # Do not exit anymore if a command fail or if a variable is empty
ynh_print_err --message="!!\n $app's script has encountered an error. Its execution was cancelled.\n!!"
if type -t ynh_clean_setup > /dev/null; then # Check if the function exist in the app script.
ynh_clean_setup # Call the function to do specific cleaning for the app.
fi
ynh_die # Exit with error status
}
# Exits if an error occurs during the execution of the script.
#
# usage: ynh_abort_if_errors
#
# This configure the rest of the script execution such that, if an error occurs
# or if an empty variable is used, the execution of the script stops
# immediately and a call to `ynh_clean_setup` is triggered if it has been
# defined by your script.
#
# Requires YunoHost version 2.6.4 or higher.
ynh_abort_if_errors () {
set -eu # Exit if a command fail, and if a variable is used unset.
trap ynh_exit_properly EXIT # Capturing exit signals on shell script
}
# Fetch the Debian release codename
#
# usage: ynh_get_debian_release
# | ret: The Debian release codename (i.e. jessie, stretch, ...)
#
# Requires YunoHost version 2.7.12 or higher.
ynh_get_debian_release () {
echo $(lsb_release --codename --short)
}
# Start (or other actions) a service, print a log in case of failure and optionnaly wait until the service is completely started
#
# usage: ynh_systemd_action [-n service_name] [-a action] [ [-l "line to match"] [-p log_path] [-t timeout] [-e length] ]
# | arg: -n, --service_name= - Name of the service to start. Default : $app
# | arg: -a, --action= - Action to perform with systemctl. Default: start
# | arg: -l, --line_match= - Line to match - The line to find in the log to attest the service have finished to boot.
# If not defined it don't wait until the service is completely started.
# WARNING: When using --line_match, you should always add `ynh_clean_check_starting` into your
# `ynh_clean_setup` at the beginning of the script. Otherwise, tail will not stop in case of failure
# of the script. The script will then hang forever.
# | arg: -p, --log_path= - Log file - Path to the log file. Default : /var/log/$app/$app.log
# | arg: -t, --timeout= - Timeout - The maximum time to wait before ending the watching. Default : 300 seconds.
# | arg: -e, --length= - Length of the error log : Default : 20
ynh_systemd_action() {
# Declare an array to define the options of this helper.
local legacy_args=nalpte
declare -Ar args_array=( [n]=service_name= [a]=action= [l]=line_match= [p]=log_path= [t]=timeout= [e]=length= )
local service_name
local action
local line_match
local length
local log_path
local timeout
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local service_name="${service_name:-$app}"
local action=${action:-start}
local log_path="${log_path:-/var/log/$service_name/$service_name.log}"
local length=${length:-20}
local timeout=${timeout:-300}
# Start to read the log
if [[ -n "${line_match:-}" ]]
then
local templog="$(mktemp)"
# Following the starting of the app in its log
if [ "$log_path" == "systemd" ] ; then
# Read the systemd journal
journalctl --unit=$service_name --follow --since=-0 --quiet > "$templog" &
# Get the PID of the journalctl command
local pid_tail=$!
else
# Read the specified log file
tail -F -n0 "$log_path" > "$templog" 2>&1 &
# Get the PID of the tail command
local pid_tail=$!
fi
fi
ynh_print_info --message="${action^} the service $service_name"
# Use reload-or-restart instead of reload. So it wouldn't fail if the service isn't running.
if [ "$action" == "reload" ]; then
action="reload-or-restart"
fi
systemctl $action $service_name \
|| ( journalctl --no-pager --lines=$length -u $service_name >&2 \
; test -e "$log_path" && echo "--" >&2 && tail --lines=$length "$log_path" >&2 \
; false )
# Start the timeout and try to find line_match
if [[ -n "${line_match:-}" ]]
then
local i=0
for i in $(seq 1 $timeout)
do
# Read the log until the sentence is found, that means the app finished to start. Or run until the timeout
if grep --quiet "$line_match" "$templog"
then
ynh_print_info --message="The service $service_name has correctly started."
break
fi
if [ $i -eq 3 ]; then
echo -n "Please wait, the service $service_name is ${action}ing" >&2
fi
if [ $i -ge 3 ]; then
echo -n "." >&2
fi
sleep 1
done
if [ $i -ge 3 ]; then
echo "" >&2
fi
if [ $i -eq $timeout ]
then
ynh_print_warn --message="The service $service_name didn't fully started before the timeout."
ynh_print_warn --message="Please find here an extract of the end of the log of the service $service_name:"
journalctl --no-pager --lines=$length -u $service_name >&2
test -e "$log_path" && echo "--" >&2 && tail --lines=$length "$log_path" >&2
fi
ynh_clean_check_starting
fi
}
# Clean temporary process and file used by ynh_check_starting
# (usually used in ynh_clean_setup scripts)
#
# usage: ynh_clean_check_starting
ynh_clean_check_starting () {
# Stop the execution of tail.
kill -s 15 $pid_tail 2>&1
ynh_secure_remove "$templog" 2>&1
}
# Read the value of a key in a ynh manifest file
#
# usage: ynh_read_manifest manifest key
# | arg: -m, --manifest= - Path of the manifest to read
# | arg: -k, --key= - Name of the key to find
#
# Requires YunoHost version 3.?.? or higher.
ynh_read_manifest () {
# Declare an array to define the options of this helper.
local legacy_args=mk
declare -Ar args_array=( [m]=manifest= [k]=manifest_key= )
local manifest
local manifest_key
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
if [ ! -e "$manifest" ]; then
# If the manifest isn't found, try the common place for backup and restore script.
manifest="../settings/manifest.json"
fi
jq ".$manifest_key" "$manifest" --raw-output
}
# Read the upstream version from the manifest
# The version number in the manifest is defined by <upstreamversion>~ynh<packageversion>
# For example : 4.3-2~ynh3
# This include the number before ~ynh
# In the last example it return 4.3-2
#
# usage: ynh_app_upstream_version [-m manifest]
# | arg: -m, --manifest= - Path of the manifest to read
#
# Requires YunoHost version 3.?.? or higher.
ynh_app_upstream_version () {
# Declare an array to define the options of this helper.
local legacy_args=m
declare -Ar args_array=( [m]=manifest= )
local manifest
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
manifest="${manifest:-../manifest.json}"
version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
echo "${version_key/~ynh*/}"
}
# Read package version from the manifest
# The version number in the manifest is defined by <upstreamversion>~ynh<packageversion>
# For example : 4.3-2~ynh3
# This include the number after ~ynh
# In the last example it return 3
#
# usage: ynh_app_package_version [-m manifest]
# | arg: -m, --manifest= - Path of the manifest to read
#
# Requires YunoHost version 3.?.? or higher.
ynh_app_package_version () {
# Declare an array to define the options of this helper.
local legacy_args=m
declare -Ar args_array=( [m]=manifest= )
local manifest
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
manifest="${manifest:-../manifest.json}"
version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
echo "${version_key/*~ynh/}"
}
# Checks the app version to upgrade with the existing app version and returns:
# - UPGRADE_APP if the upstream app version has changed
# - UPGRADE_PACKAGE if only the YunoHost package has changed
#
# It stops the current script without error if the package is up-to-date
#
# This helper should be used to avoid an upgrade of an app, or the upstream part
# of it, when it's not needed
#
# To force an upgrade, even if the package is up to date,
# you have to set the variable YNH_FORCE_UPGRADE before.
# example: sudo YNH_FORCE_UPGRADE=1 yunohost app upgrade MyApp
#
# usage: ynh_check_app_version_changed
#
# Requires YunoHost version 3.?.? or higher.
ynh_check_app_version_changed () {
local force_upgrade=${YNH_FORCE_UPGRADE:-0}
local package_check=${PACKAGE_CHECK_EXEC:-0}
# By default, upstream app version has changed
local return_value="UPGRADE_APP"
local current_version=$(ynh_read_manifest --manifest="/etc/yunohost/apps/$YNH_APP_INSTANCE_NAME/manifest.json" --manifest_key="version" || echo 1.0)
local current_upstream_version="$(ynh_app_upstream_version --manifest="/etc/yunohost/apps/$YNH_APP_INSTANCE_NAME/manifest.json")"
local update_version=$(ynh_read_manifest --manifest="../manifest.json" --manifest_key="version" || echo 1.0)
local update_upstream_version="$(ynh_app_upstream_version)"
if [ "$current_version" == "$update_version" ] ; then
# Complete versions are the same
if [ "$force_upgrade" != "0" ]
then
ynh_print_info --message="Upgrade forced by YNH_FORCE_UPGRADE."
unset YNH_FORCE_UPGRADE
elif [ "$package_check" != "0" ]
then
ynh_print_info --message="Upgrade forced for package check."
else
ynh_die "Up-to-date, nothing to do" 0
fi
elif [ "$current_upstream_version" == "$update_upstream_version" ] ; then
# Upstream versions are the same, only YunoHost package versions differ
return_value="UPGRADE_PACKAGE"
fi
echo $return_value
}

179
data/helpers.d/systemd Normal file
View file

@ -0,0 +1,179 @@
#!/bin/bash
# Create a dedicated systemd config
#
# usage: ynh_add_systemd_config [--service=service] [--template=template]
# | arg: -s, --service - Service name (optionnal, $app by default)
# | arg: -t, --template - Name of template file (optionnal, this is 'systemd' by default, meaning ./conf/systemd.service will be used as template)
#
# This will use the template ../conf/<templatename>.service
# to generate a systemd config, by replacing the following keywords
# with global variables that should be defined before calling
# this helper :
#
# __APP__ by $app
# __FINALPATH__ by $final_path
#
# Requires YunoHost version 2.7.2 or higher.
ynh_add_systemd_config () {
# Declare an array to define the options of this helper.
local legacy_args=st
declare -Ar args_array=( [s]=service= [t]=template= )
local service
local template
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local service="${service:-$app}"
local template="${template:-systemd.service}"
finalsystemdconf="/etc/systemd/system/$service.service"
ynh_backup_if_checksum_is_different --file="$finalsystemdconf"
sudo cp ../conf/$template "$finalsystemdconf"
# To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable.
# Substitute in a nginx config file only if the variable is not empty
if test -n "${final_path:-}"; then
ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalsystemdconf"
fi
if test -n "${app:-}"; then
ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="$finalsystemdconf"
fi
ynh_store_file_checksum --file="$finalsystemdconf"
sudo chown root: "$finalsystemdconf"
sudo systemctl enable $service
sudo systemctl daemon-reload
}
# Remove the dedicated systemd config
#
# usage: ynh_remove_systemd_config [--service=service]
# | arg: -s, --service - Service name (optionnal, $app by default)
#
# Requires YunoHost version 2.7.2 or higher.
ynh_remove_systemd_config () {
# Declare an array to define the options of this helper.
local legacy_args=s
declare -Ar args_array=( [s]=service= )
local service
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local service="${service:-$app}"
local finalsystemdconf="/etc/systemd/system/$service.service"
if [ -e "$finalsystemdconf" ]; then
ynh_systemd_action --service_name=$service --action=stop
systemctl disable $service
ynh_secure_remove --file="$finalsystemdconf"
systemctl daemon-reload
fi
}
# Start (or other actions) a service, print a log in case of failure and optionnaly wait until the service is completely started
#
# usage: ynh_systemd_action [-n service_name] [-a action] [ [-l "line to match"] [-p log_path] [-t timeout] [-e length] ]
# | arg: -n, --service_name= - Name of the service to start. Default : $app
# | arg: -a, --action= - Action to perform with systemctl. Default: start
# | arg: -l, --line_match= - Line to match - The line to find in the log to attest the service have finished to boot.
# If not defined it don't wait until the service is completely started.
# WARNING: When using --line_match, you should always add `ynh_clean_check_starting` into your
# `ynh_clean_setup` at the beginning of the script. Otherwise, tail will not stop in case of failure
# of the script. The script will then hang forever.
# | arg: -p, --log_path= - Log file - Path to the log file. Default : /var/log/$app/$app.log
# | arg: -t, --timeout= - Timeout - The maximum time to wait before ending the watching. Default : 300 seconds.
# | arg: -e, --length= - Length of the error log : Default : 20
ynh_systemd_action() {
# Declare an array to define the options of this helper.
local legacy_args=nalpte
declare -Ar args_array=( [n]=service_name= [a]=action= [l]=line_match= [p]=log_path= [t]=timeout= [e]=length= )
local service_name
local action
local line_match
local length
local log_path
local timeout
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local service_name="${service_name:-$app}"
local action=${action:-start}
local log_path="${log_path:-/var/log/$service_name/$service_name.log}"
local length=${length:-20}
local timeout=${timeout:-300}
# Start to read the log
if [[ -n "${line_match:-}" ]]
then
local templog="$(mktemp)"
# Following the starting of the app in its log
if [ "$log_path" == "systemd" ] ; then
# Read the systemd journal
journalctl --unit=$service_name --follow --since=-0 --quiet > "$templog" &
# Get the PID of the journalctl command
local pid_tail=$!
else
# Read the specified log file
tail -F -n0 "$log_path" > "$templog" 2>&1 &
# Get the PID of the tail command
local pid_tail=$!
fi
fi
ynh_print_info --message="${action^} the service $service_name"
# Use reload-or-restart instead of reload. So it wouldn't fail if the service isn't running.
if [ "$action" == "reload" ]; then
action="reload-or-restart"
fi
systemctl $action $service_name \
|| ( journalctl --no-pager --lines=$length -u $service_name >&2 \
; test -e "$log_path" && echo "--" >&2 && tail --lines=$length "$log_path" >&2 \
; false )
# Start the timeout and try to find line_match
if [[ -n "${line_match:-}" ]]
then
local i=0
for i in $(seq 1 $timeout)
do
# Read the log until the sentence is found, that means the app finished to start. Or run until the timeout
if grep --quiet "$line_match" "$templog"
then
ynh_print_info --message="The service $service_name has correctly started."
break
fi
if [ $i -eq 3 ]; then
echo -n "Please wait, the service $service_name is ${action}ing" >&2
fi
if [ $i -ge 3 ]; then
echo -n "." >&2
fi
sleep 1
done
if [ $i -ge 3 ]; then
echo "" >&2
fi
if [ $i -eq $timeout ]
then
ynh_print_warn --message="The service $service_name didn't fully started before the timeout."
ynh_print_warn --message="Please find here an extract of the end of the log of the service $service_name:"
journalctl --no-pager --lines=$length -u $service_name >&2
test -e "$log_path" && echo "--" >&2 && tail --lines=$length "$log_path" >&2
fi
ynh_clean_check_starting
fi
}
# Clean temporary process and file used by ynh_check_starting
# (usually used in ynh_clean_setup scripts)
#
# usage: ynh_clean_check_starting
ynh_clean_check_starting () {
# Stop the execution of tail.
kill -s 15 $pid_tail 2>&1
ynh_secure_remove "$templog" 2>&1
}

View file

@ -1,113 +1,53 @@
#!/bin/bash
# Extract a key from a plain command output
# Manage a fail of the script
#
# example: yunohost user info tata --output-as plain | ynh_get_plain_key mail
#
# usage: ynh_get_plain_key key [subkey [subsubkey ...]]
# | ret: string - the key's value
#
# Requires YunoHost version 2.2.4 or higher.
ynh_get_plain_key() {
local prefix="#"
local founded=0
local key=$1
shift
while read line; do
if [[ "$founded" == "1" ]] ; then
[[ "$line" =~ ^${prefix}[^#] ]] && return
echo $line
elif [[ "$line" =~ ^${prefix}${key}$ ]]; then
if [[ -n "${1:-}" ]]; then
prefix+="#"
key=$1
shift
else
founded=1
fi
fi
done
}
# Restore a previous backup if the upgrade process failed
# [internal]
#
# usage:
# ynh_backup_before_upgrade
# ynh_exit_properly is used only by the helper ynh_abort_if_errors.
# You should not use it directly.
# Instead, add to your script:
# ynh_clean_setup () {
# ynh_restore_upgradebackup
# instructions...
# }
# ynh_abort_if_errors
#
# Requires YunoHost version 2.7.2 or higher.
ynh_restore_upgradebackup () {
ynh_print_err --message="Upgrade failed."
local app_bck=${app//_/-} # Replace all '_' by '-'
NO_BACKUP_UPGRADE=${NO_BACKUP_UPGRADE:-0}
if [ "$NO_BACKUP_UPGRADE" -eq 0 ]
then
# Check if an existing backup can be found before removing and restoring the application.
if sudo yunohost backup list | grep -q $app_bck-pre-upgrade$backup_number
then
# Remove the application then restore it
sudo yunohost app remove $app
# Restore the backup
sudo yunohost backup restore $app_bck-pre-upgrade$backup_number --apps $app --force --debug
ynh_die --message="The app was restored to the way it was before the failed upgrade."
# This function provide a way to clean some residual of installation that not managed by remove script.
#
# It prints a warning to inform that the script was failed, and execute the ynh_clean_setup function if used in the app script
#
# Requires YunoHost version 2.6.4 or higher.
ynh_exit_properly () {
local exit_code=$?
if [ "$exit_code" -eq 0 ]; then
exit 0 # Exit without error if the script ended correctly
fi
else
ynh_print_warn --message="\$NO_BACKUP_UPGRADE is set, that means there's no backup to restore. You have to fix this upgrade by yourself !"
trap '' EXIT # Ignore new exit signals
set +eu # Do not exit anymore if a command fail or if a variable is empty
ynh_print_err --message="!!\n $app's script has encountered an error. Its execution was cancelled.\n!!"
if type -t ynh_clean_setup > /dev/null; then # Check if the function exist in the app script.
ynh_clean_setup # Call the function to do specific cleaning for the app.
fi
ynh_die # Exit with error status
}
# Make a backup in case of failed upgrade
# Exits if an error occurs during the execution of the script.
#
# usage:
# ynh_backup_before_upgrade
# ynh_clean_setup () {
# ynh_restore_upgradebackup
# }
# ynh_abort_if_errors
# usage: ynh_abort_if_errors
#
# Requires YunoHost version 2.7.2 or higher.
ynh_backup_before_upgrade () {
if [ ! -e "/etc/yunohost/apps/$app/scripts/backup" ]
then
ynh_print_warn --message="This app doesn't have any backup script."
return
fi
backup_number=1
local old_backup_number=2
local app_bck=${app//_/-} # Replace all '_' by '-'
NO_BACKUP_UPGRADE=${NO_BACKUP_UPGRADE:-0}
if [ "$NO_BACKUP_UPGRADE" -eq 0 ]
then
# Check if a backup already exists with the prefix 1
if sudo yunohost backup list | grep -q $app_bck-pre-upgrade1
then
# Prefix becomes 2 to preserve the previous backup
backup_number=2
old_backup_number=1
fi
# Create backup
sudo BACKUP_CORE_ONLY=1 yunohost backup create --apps $app --name $app_bck-pre-upgrade$backup_number --debug
if [ "$?" -eq 0 ]
then
# If the backup succeeded, remove the previous backup
if sudo yunohost backup list | grep -q $app_bck-pre-upgrade$old_backup_number
then
# Remove the previous backup only if it exists
sudo yunohost backup delete $app_bck-pre-upgrade$old_backup_number > /dev/null
fi
else
ynh_die --message="Backup failed, the upgrade process was aborted."
fi
else
ynh_print_warn --message="\$NO_BACKUP_UPGRADE is set, backup will be avoided. Be careful, this upgrade is going to be operated without a security backup"
fi
# This configure the rest of the script execution such that, if an error occurs
# or if an empty variable is used, the execution of the script stops
# immediately and a call to `ynh_clean_setup` is triggered if it has been
# defined by your script.
#
# Requires YunoHost version 2.6.4 or higher.
ynh_abort_if_errors () {
set -eu # Exit if a command fail, and if a variable is used unset.
trap ynh_exit_properly EXIT # Capturing exit signals on shell script
}
# Download, check integrity, uncompress and patch the source from app.src
@ -318,3 +258,220 @@ ynh_render_template() {
jinja2.Template(sys.stdin.read()
).render(os.environ));' < $template_path > $output_path
}
# Fetch the Debian release codename
#
# usage: ynh_get_debian_release
# | ret: The Debian release codename (i.e. jessie, stretch, ...)
#
# Requires YunoHost version 2.7.12 or higher.
ynh_get_debian_release () {
echo $(lsb_release --codename --short)
}
# Create a directory under /tmp
#
# [internal]
#
# Deprecated helper
#
# usage: ynh_mkdir_tmp
# | ret: the created directory path
ynh_mkdir_tmp() {
ynh_print_warn --message="The helper ynh_mkdir_tmp is deprecated."
ynh_print_warn --message="You should use 'mktemp -d' instead and manage permissions \
properly with chmod/chown."
local TMP_DIR=$(mktemp -d)
# Give rights to other users could be a security risk.
# But for retrocompatibility we need it. (This helpers is deprecated)
chmod 755 $TMP_DIR
echo $TMP_DIR
}
# Remove a file or a directory securely
#
# usage: ynh_secure_remove --file=path_to_remove
# | arg: -f, --file - File or directory to remove
#
# Requires YunoHost version 2.6.4 or higher.
ynh_secure_remove () {
# Declare an array to define the options of this helper.
local legacy_args=f
declare -Ar args_array=( [f]=file= )
local file
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local forbidden_path=" \
/var/www \
/home/yunohost.app"
if [ $# -ge 2 ]
then
ynh_print_warn --message="/!\ Packager ! You provided more than one argument to ynh_secure_remove but it will be ignored... Use this helper with one argument at time."
fi
if [[ "$forbidden_path" =~ "$file" \
# Match all paths or subpaths in $forbidden_path
|| "$file" =~ ^/[[:alnum:]]+$ \
# Match all first level paths from / (Like /var, /root, etc...)
|| "${file:${#file}-1}" = "/" ]]
# Match if the path finishes by /. Because it seems there is an empty variable
then
ynh_print_warn --message="Avoid deleting $file."
else
if [ -e "$file" ]
then
sudo rm -R "$file"
else
ynh_print_info --message="$file wasn't deleted because it doesn't exist."
fi
fi
}
# Extract a key from a plain command output
#
# example: yunohost user info tata --output-as plain | ynh_get_plain_key mail
#
# usage: ynh_get_plain_key key [subkey [subsubkey ...]]
# | ret: string - the key's value
#
# Requires YunoHost version 2.2.4 or higher.
ynh_get_plain_key() {
local prefix="#"
local founded=0
local key=$1
shift
while read line; do
if [[ "$founded" == "1" ]] ; then
[[ "$line" =~ ^${prefix}[^#] ]] && return
echo $line
elif [[ "$line" =~ ^${prefix}${key}$ ]]; then
if [[ -n "${1:-}" ]]; then
prefix+="#"
key=$1
shift
else
founded=1
fi
fi
done
}
# Read the value of a key in a ynh manifest file
#
# usage: ynh_read_manifest manifest key
# | arg: -m, --manifest= - Path of the manifest to read
# | arg: -k, --key= - Name of the key to find
#
# Requires YunoHost version 3.?.? or higher.
ynh_read_manifest () {
# Declare an array to define the options of this helper.
local legacy_args=mk
declare -Ar args_array=( [m]=manifest= [k]=manifest_key= )
local manifest
local manifest_key
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
if [ ! -e "$manifest" ]; then
# If the manifest isn't found, try the common place for backup and restore script.
manifest="../settings/manifest.json"
fi
jq ".$manifest_key" "$manifest" --raw-output
}
# Read the upstream version from the manifest
# The version number in the manifest is defined by <upstreamversion>~ynh<packageversion>
# For example : 4.3-2~ynh3
# This include the number before ~ynh
# In the last example it return 4.3-2
#
# usage: ynh_app_upstream_version [-m manifest]
# | arg: -m, --manifest= - Path of the manifest to read
#
# Requires YunoHost version 3.?.? or higher.
ynh_app_upstream_version () {
# Declare an array to define the options of this helper.
local legacy_args=m
declare -Ar args_array=( [m]=manifest= )
local manifest
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
manifest="${manifest:-../manifest.json}"
version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
echo "${version_key/~ynh*/}"
}
# Read package version from the manifest
# The version number in the manifest is defined by <upstreamversion>~ynh<packageversion>
# For example : 4.3-2~ynh3
# This include the number after ~ynh
# In the last example it return 3
#
# usage: ynh_app_package_version [-m manifest]
# | arg: -m, --manifest= - Path of the manifest to read
#
# Requires YunoHost version 3.?.? or higher.
ynh_app_package_version () {
# Declare an array to define the options of this helper.
local legacy_args=m
declare -Ar args_array=( [m]=manifest= )
local manifest
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
manifest="${manifest:-../manifest.json}"
version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
echo "${version_key/*~ynh/}"
}
# Checks the app version to upgrade with the existing app version and returns:
# - UPGRADE_APP if the upstream app version has changed
# - UPGRADE_PACKAGE if only the YunoHost package has changed
#
# It stops the current script without error if the package is up-to-date
#
# This helper should be used to avoid an upgrade of an app, or the upstream part
# of it, when it's not needed
#
# To force an upgrade, even if the package is up to date,
# you have to set the variable YNH_FORCE_UPGRADE before.
# example: sudo YNH_FORCE_UPGRADE=1 yunohost app upgrade MyApp
#
# usage: ynh_check_app_version_changed
#
# Requires YunoHost version 3.?.? or higher.
ynh_check_app_version_changed () {
local force_upgrade=${YNH_FORCE_UPGRADE:-0}
local package_check=${PACKAGE_CHECK_EXEC:-0}
# By default, upstream app version has changed
local return_value="UPGRADE_APP"
local current_version=$(ynh_read_manifest --manifest="/etc/yunohost/apps/$YNH_APP_INSTANCE_NAME/manifest.json" --manifest_key="version" || echo 1.0)
local current_upstream_version="$(ynh_app_upstream_version --manifest="/etc/yunohost/apps/$YNH_APP_INSTANCE_NAME/manifest.json")"
local update_version=$(ynh_read_manifest --manifest="../manifest.json" --manifest_key="version" || echo 1.0)
local update_upstream_version="$(ynh_app_upstream_version)"
if [ "$current_version" == "$update_version" ] ; then
# Complete versions are the same
if [ "$force_upgrade" != "0" ]
then
ynh_print_info --message="Upgrade forced by YNH_FORCE_UPGRADE."
unset YNH_FORCE_UPGRADE
elif [ "$package_check" != "0" ]
then
ynh_print_info --message="Upgrade forced for package check."
else
ynh_die "Up-to-date, nothing to do" 0
fi
elif [ "$current_upstream_version" == "$update_upstream_version" ] ; then
# Upstream versions are the same, only YunoHost package versions differ
return_value="UPGRADE_PACKAGE"
fi
echo $return_value
}