scripts/proxmox/backup.pve.content.sh

291 lines
7.9 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
# This script will backup /etc/pve content :
# 1. Make an archive to a first directory (default: /etc/proxmox.pve/backup/).
# 2. Hard link a fix archive name (pve.latest.tar.gz) to new archive
# Easy to monitor (eg. this path can be expected).
# 3. Limit permissions to backup directory (default: backup:adm).
# 4. Clean backups older than retention time (default: 7).
# 5. (optionnal) Copy backup to a second directory (nfs mountpoint, other hdd,…).
#
# This script can be call by a cronjob (eg. daily).
# Vars {{{
readonly PROGNAME=$(basename "${0}")
readonly PROGDIR=$(readlink -m $(dirname "${0}"))
readonly ARGS="${*}"
readonly NBARGS="${#}"
[ -z "${DEBUG}" ] && DEBUG=1
readonly DEFAULT_FIRST_BKP_DIR="/etc/proxmox.pve/backup"
readonly TODAY_VAR=$(date +%Y%m%d)
readonly DEFAULT_RETENTION_TIME="7"
readonly DEFAULT_USER="backup"
readonly DEFAULT_GROUP="adm"
## Colors
readonly PURPLE='\033[1;35m'
readonly RED='\033[0;31m'
readonly RESET='\033[0m'
readonly COLOR_DEBUG="${PURPLE}"
# }}}
usage() { # {{{
cat <<- EOF
usage: $PROGNAME [-d|-f|-g|-h|-r|-s|-u]
Backup /etc/pve content.
EXAMPLES:
- Backup /etc/pve content to ${DEFAULT_FIRST_BKP_DIR} directory
${PROGNAME}
- Backup /etc/pve content to /var/backups/pve directory
${PROGNAME} --first-directory /var/backups/pve
- Backup to default path and keep backups for 14 days
${PROGNAME} --retention 14
- Duplicate backups to a second directory (/mnt/nfs/pve)
${PROGNAME} --second-directory /mnt/nfs/pve
OPTIONS:
-d,--debug
Enable debug messages.
-f,--first,--first-directory
Path to a first directory to store backup
And override default path ${DEFAULT_FIRST_BKP_DIR}.
-g,--group
Group of the backup files (default: ${DEFAULT_GROUP}).
-h,--help
Print this help message.
-r,--retention,--retention-time
Backups older than retention time (default: ${DEFAULT_RETENTION_TIME})
will be delete.
-s,--second,--second-directory
Path to a second directory to duplicate backups (default: not set).
-u,--user
Owner of the backup files (default: ${DEFAULT_USER}).
EOF
}
# }}}
debug_message() { # {{{
local_message="${1}"
## Print message if DEBUG is enable (=0)
[ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6b\e[m\n' "DEBUG ${PROGNAME}: ${local_message}"
return 0
}
# }}}
define_vars() { # {{{
## If first_bkp_dir wasn't defined {{{
if [ -z "${first_bkp_dir}" ]; then
## Use default path to store backup
first_bkp_dir="${DEFAULT_FIRST_BKP_DIR}"
fi
## }}}
## If retention_time wasn't defined {{{
if [ -z "${retention_time}" ]; then
## Use default retention time to clean backups
retention_time="${DEFAULT_RETENTION_TIME}"
fi
## }}}
## If user_bkp_dir wasn't defined {{{
if [ -z "${user_bkp_dir}" ]; then
## Use default user as owner of backup files
user_bkp_dir="${DEFAULT_USER}"
fi
## }}}
## If group_bkp_dir wasn't defined {{{
if [ -z "${group_bkp_dir}" ]; then
## Use default group for backup files
group_bkp_dir="${DEFAULT_GROUP}"
fi
## }}}
}
# }}}
is_directory_absent() { # {{{
local_directory_absent="${1}"
## Directory exists by default
return_is_directory_absent="1"
### Check if the directory exists
# shellcheck disable=SC2086
if test -d "${local_directory_absent}"; then
return_is_directory_absent="1"
debug_message "is_directory_absent \
The directory ${RED}${local_directory_absent}${COLOR_DEBUG} exists."
else
return_is_directory_absent="0"
debug_message "is_directory_absent \
The directory ${RED}${local_directory_absent}${COLOR_DEBUG} doesn't exist."
fi
return "${return_is_directory_absent}"
}
# }}}
main() { # {{{
## Define all vars
define_vars
## Verify if /etc/pve directory is absent {{{
### Display an explicit error message
### AND exit with error code 1
is_directory_absent /etc/pve \
&& printf '%b\n' "${RED}/etc/pve directory doesn't seems available. Are you sure you run this script on a Proxmox host?${RESET}" \
&& exit 1
## }}}
## Verify if the first destination directory is absent {{{
### AND create it
is_directory_absent "${first_bkp_dir}" \
&& mkdir -p -- "${first_bkp_dir}"
## }}}
## Create an archive of /etc/pve to $first_bkp_dir {{{
### OR exit with error code 2 if it fails
tar --exclude='*/lock' -czf "${first_bkp_dir}/pve.${TODAY_VAR}.tar.gz" -C /etc/ pve/ \
|| exit 2
## }}}
## Create an hard link to pve.latest.tar.gz {{{
### OR exit with error code 3 if it fails
ln --force -- "${first_bkp_dir}/pve.${TODAY_VAR}.tar.gz" "${first_bkp_dir}/pve.latest.tar.gz" \
|| exit 3
## }}}
## Fix backups permissions {{{
### Only readable by specified user:group (default: backup:adm)
chown -R "${user_bkp_dir}:${group_bkp_dir}" -- "${first_bkp_dir}" \
&& chmod 'u+rwX,g+rX,o-rwx' -R -- "${first_bkp_dir}"
## }}}
## Clean files older than $retention_time {{{
### OR exit with error code 4 if it fails
find "${first_bkp_dir}" -maxdepth 1 -type f -mtime +"${retention_time}" -iname "pve.*.tar.gz" -delete \
|| exit 4
## }}}
## If second directory is defined {{{
if [ -n "${second_bkp_dir}" ]; then
### Verify if the second destination directory is absent {{{
#### AND create it
is_directory_absent "${second_bkp_dir}" \
&& mkdir -p -- "${second_bkp_dir}"
### }}}
### Synchronize first directory to second {{{
#### OR exit with error code 12 if it fails
#### rsync "-a" option might fail with some network share
#### So, remove --group and --owner options
rsync --recursive --links --perms --times -D -- "${first_bkp_dir}/" "${second_bkp_dir}/" \
|| exit 12
### }}}
fi
## }}}
}
# }}}
# Manage arguments # {{{
# This code can't be in a function due to argument management
if [ ! "${NBARGS}" -eq "0" ]; then
manage_arg="0"
## If the first argument is not an option
if ! printf -- '%s' "${1}" | grep -q -E -- "^-+";
then
## Print help message and exit
printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
printf '%b\n' "---"
usage
exit 1
fi
# Parse all options (start with a "-") one by one
while printf -- '%s' "${1}" | grep -q -E -- "^-+"; do
case "${1}" in
-d|--debug ) ## debug
DEBUG=0
;;
-f|--first|--first-directory ) ## first directory to store backup
## Move to the next argument
shift
## Define first_bkp_dir
first_bkp_dir="${1}"
;;
-g|--group ) ## group of backup files
## Move to the next argument
shift
## Define group_bkp_dir
group_bkp_dir="${1}"
;;
-h|--help ) ## help
usage
## Exit after help informations
exit 0
;;
-r|--retention,--retention-time ) ## clean backups older than retention time
## Move to the next argument
shift
## Define retention_time
retention_time="${1}"
;;
-s|--second|--second-directory ) ## second directory to duplicate backup
## Move to the next argument
shift
## Define second_bkp_dir
second_bkp_dir="${1}"
;;
-u|--user ) ## owner of backup files
## Move to the next argument
shift
## Define user_bkp_dir
user_bkp_dir="${1}"
;;
* ) ## unknow option
printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
printf '%b\n' "---"
usage
exit 1
;;
esac
debug_message "Arguments management \
${RED}${1}${COLOR_DEBUG} option managed."
## Move to the next argument
shift
manage_arg=$((manage_arg+1))
done
debug_message "Arguments management \
${RED}${manage_arg}${COLOR_DEBUG} argument(s) successfully managed."
else
debug_message "Arguments management \
No arguments/options to manage."
fi
# }}}
main
exit 0