helpers2.1: further simplify ynh_backup/restore: use a single positional arg. --is_big behavior is replaced by checking if the path is $data_dir (or a child) or /var/log/$app. --not_mandatory for restore is implied using the same check, or should be replaced by || true on the package side for the few cases where it's related to other stuff than the data dir or log dir

This commit is contained in:
Alexandre Aubin 2024-06-11 02:13:28 +02:00
parent c5815fb1ef
commit 0c319cbeba

View file

@ -4,85 +4,48 @@ CAN_BIND=${CAN_BIND:-1}
# Add a file or a directory to the list of paths to backup
#
# usage: ynh_backup --target=/path/to/stuff [--is_big] [--not_mandatory]
# | arg: -s, --target= - file or directory to bind or symlink or copy. it shouldn't be in the backup dir.
# | arg: -b, --is_big - Indicate data are big (mail, video, image ...)
# | arg: -m, --not_mandatory - Indicate that if the file is missing, the backup can ignore it.
# usage: ynh_backup /path/to/stuff
#
# This helper can be used both in a system backup hook, and in an app backup script
# NB : note that this helper does *NOT* perform any copy in itself, it only
# declares stuff to be backuped via a CSV which is later picked up by the core
#
# `ynh_backup` writes `target` and the corresponding path inside the archive (dest_path) into a CSV file, and it
# creates the parent destination directory
# NB 2 : there is a specific behavior for $data_dir (or childs of $data_dir) and
# /var/log/$app which are *NOT* backedup during safety-backup-before-upgrade,
# OR if the setting "do_not_backup_data" is equals 1 for that app
#
# Example in the context of a wordpress app :
# ```
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf"
# # => This line will be added into CSV file
# # "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/etc/nginx/conf.d/$domain.d/$app.conf"
# The rationale is that these directories are usually too heavy to be integrated in every backup
# (think for example about Nextcloud with quite a lot of data, or an app with a lot of media files...)
#
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "conf/nginx.conf"
# # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/nginx.conf"
# This is coupled to the fact that $data_dir and the log dir won't be (and
# should NOT) be deleted during remove, unless --purge is used. Hence, if the
# upgrade fails and the script is removed prior to restoring the backup, the
# data/logs are not destroyed.
#
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "conf/"
# # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/$app.conf"
#
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "conf"
# # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf"
#
# #Deprecated usages (maintained for retro-compatibility)
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "${backup_dir}/conf/nginx.conf"
# # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/nginx.conf"
#
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "/conf/"
# # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/$app.conf"
#
# ```
#
# How to use `--is_big`:
#
# `--is_big` is used to specify that this part of the backup can be quite huge.
# So, you don't want that your package does backup that part during ynh_backup_before_upgrade.
# In the same way, an user may doesn't want to backup this big part of the app for
# each of his backup. And so handle that part differently.
#
# As this part of your backup may not be done, your restore script has to handle it.
# In your restore script, use `--not_mandatory` with `ynh_restore`
# As well in your remove script, you should not remove those data ! Or an user may end up with
# a failed upgrade restoring an app without data anymore !
#
# To have the benefit of `--is_big` while doing a backup, you can whether set the environement
# variable `BACKUP_CORE_ONLY` to 1 (`BACKUP_CORE_ONLY=1`) before the backup command. It will affect
# only that backup command.
# Or set the config `do_not_backup_data` to 1 into the `settings.yml` of the app. This will affect
# all backups for this app until the setting is removed.
#
# Requires YunoHost version 2.4.0 or higher.
# Requires YunoHost version 3.5.0 or higher for the argument `--not_mandatory`
ynh_backup() {
# TODO find a way to avoid injection by file strange naming !
# ============ Argument parsing =============
local -A args_array=([t]=target= [b]=is_big [m]=not_mandatory)
local target
local is_big
local not_mandatory
ynh_handle_getopts_args "$@"
is_big="${is_big:-0}"
not_mandatory="${not_mandatory:-0}"
# ===========================================
local target="$1"
local is_data=false
BACKUP_CORE_ONLY=${BACKUP_CORE_ONLY:-0}
test -n "${app:-}" && do_not_backup_data=$(ynh_app_setting_get --key=do_not_backup_data)
# If the path starts with /var/log/$app or $data_dir
if ([[ -n "${app:-}" ]] && [[ "$target" == "/var/log/$app*" ]]) || ([[ -n "${data_dir:-}" ]] && [[ "$target" == "$data_dir*" ]])
then
is_data=true
fi
if [[ -n "${app:-}" ]]
then
local do_not_backup_data=$(ynh_app_setting_get --key=do_not_backup_data)
fi
# If backing up core only (used by ynh_backup_before_upgrade),
# don't backup big data items
if [ $is_big -eq 1 ] && ([ ${do_not_backup_data:-0} -eq 1 ] || [ $BACKUP_CORE_ONLY -eq 1 ]); then
if [[ "$is_data" == true ]] && ([[ ${do_not_backup_data:-0} -eq 1 ]] || [[ ${BACKUP_CORE_ONLY:-0} -eq 1 ]]); then
if [ $BACKUP_CORE_ONLY -eq 1 ]; then
ynh_print_info --message="$target will not be saved, because 'BACKUP_CORE_ONLY' is set."
else
ynh_print_info --message="$target will not be saved, because 'do_not_backup_data' is set."
fi
return 0
return 1
fi
# ==============================================================================
@ -90,12 +53,8 @@ ynh_backup() {
# ==============================================================================
# Be sure the source path is not empty
if [ ! -e "$target" ]; then
ynh_print_warn --message="Source path '${src_path}' does not exist"
if [ "$not_mandatory" == "0" ]; then
ynh_print_warn --message="File or folder '${target}' to be backed up does not exist"
return 1
else
return 0
fi
fi
# Transform the source path as an absolute path
@ -154,46 +113,45 @@ with open(sys.argv[1], 'r') as backup_file:
return $?
}
# Restore a file or a directory
# Restore a file or a directory from the backup archive
#
# usage: ynh_restore --target=/path/to/stuff [--not_mandatory]
# | arg: -t, --target= - Path where was located the file or the directory before to be backuped or relative path to $YNH_CWD where it is located in the backup archive
# | arg: -m, --not_mandatory - Indicate that if the file is missing, the restore process can ignore it.
#
# Use the registered path in backup_list by ynh_backup to restore the file at the right place.
# usage: ynh_restore /path/to/stuff
#
# examples:
# ynh_restore -t "/etc/nginx/conf.d/$domain.d/$app.conf"
# # You can also use relative paths:
# ynh_restore -t "conf/nginx.conf"
# ynh_restore "/etc/nginx/conf.d/$domain.d/$app.conf"
#
# If `DEST_PATH` already exists and is lighter than 500 Mo, a backup will be made in
# `/var/cache/yunohost/appconfbackup/`. Otherwise, the existing file is removed.
# If the file or dir to be restored already exists on the system and is lighter
# than 500 Mo, it is backed up in `/var/cache/yunohost/appconfbackup/`.
# Otherwise, the existing file or dir is removed.
#
# if `apps/$app/etc/nginx/conf.d/$domain.d/$app.conf` exists, restore it into
# `/etc/nginx/conf.d/$domain.d/$app.conf`
# if no, search for a match in the csv (eg: conf/nginx.conf) and restore it into
# otheriwse, search for a match in the csv (eg: conf/nginx.conf) and restore it into
# `/etc/nginx/conf.d/$domain.d/$app.conf`
#
# Requires YunoHost version 2.6.4 or higher.
# Requires YunoHost version 3.5.0 or higher for the argument --not_mandatory
ynh_restore() {
# ============ Argument parsing =============
local -A args_array=([t]=target= [m]=not_mandatory)
local target
local not_mandatory
ynh_handle_getopts_args "$@"
target="/${target#/}"
not_mandatory="${not_mandatory:-0}"
# ===========================================
target="$1"
local archive_path="$YNH_CWD${target}"
# If the path starts with /var/log/$app or $data_dir
local is_data=false
if ([[ -n "${app:-}" ]] && [[ "$target" == "/var/log/$app*" ]]) || ([[ -n "${data_dir:-}" ]] && [[ "$target" == "$data_dir*" ]])
then
is_data=true
fi
# If archive_path doesn't exist, search for a corresponding path in CSV
if [ ! -d "$archive_path" ] && [ ! -f "$archive_path" ] && [ ! -L "$archive_path" ]; then
if [ "$not_mandatory" == "0" ]; then
archive_path="$YNH_BACKUP_DIR/$(_get_archive_path \"$target\")"
else
if [[ "$is_data" == true ]]
then
ynh_print_info --message="Skipping $target which doesn't exists in the archive, probably because restoring from a safety-backup-before-upgrade"
# Assume it's not a big deal, we may be restoring a safety-backup-before-upgrade which doesnt contain those
return 0
else
# (get_archive_path will raise an exception if no match found)
archive_path="$YNH_BACKUP_DIR/$(_get_archive_path \"$target\")"
fi
fi
@ -239,7 +197,7 @@ ynh_restore_everything() {
cat ${YNH_BACKUP_CSV} | tr --delete $'\r' | grep --only-matching --no-filename --perl-regexp "^\".*\",\"$REL_DIR.*\"$" \
| while read line; do
local ARCHIVE_PATH=$(echo "$line" | grep --only-matching --no-filename --perl-regexp "^\".*\",\"$REL_DIR\K.*(?=\"$)")
ynh_restore --target="$ARCHIVE_PATH"
ynh_restore "$ARCHIVE_PATH"
done
}