First Commit
This commit is contained in:
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Jonas Friedmann
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
89
README.md
Normal file
89
README.md
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
tar-multibackup
|
||||||
|
===============
|
||||||
|
Bash script to backup multiple folders and to clean up old backups based on a retention time. Features configurable post/pre-commands, tar excludes as well as backup retentions.
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
cd /usr/local/src
|
||||||
|
git clone https://github.com/frdmn/tar-multibackup.git
|
||||||
|
ln -sf /usr/local/src/tar-multibackup/multibackup /usr/local/bin/multibackup
|
||||||
|
cp /usr/local/src/tar-multibackup/multibackup.conf ~/.multibackup.conf
|
||||||
|
|
||||||
|
### Configuration and usage
|
||||||
|
|
||||||
|
* `timestamp` = Format of the timestamp, used in the backup target filename
|
||||||
|
* `backup_destination` = Directory which is used to store the archives/backups
|
||||||
|
* `folders_to_backup` = Array of folders to backup
|
||||||
|
* `backup_retention` = Retention time how long we should keep the backups
|
||||||
|
* `pre_commands` = Array of commands that are executed before the backup starts (stop specific service)
|
||||||
|
* `post_commands` = Array of commands that are executed after the backup finished (start specific service)
|
||||||
|
* `tar_options` = Additional tar Options
|
||||||
|
|
||||||
|
### Environment configurations
|
||||||
|
|
||||||
|
* `DEBUG` = if set to "true", `set -x` will be set
|
||||||
|
* `CONFIG` = if you want to use a different configuration file than the
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
CONFIG=/tmp/testbackup.conf DEBUG=true multibackup
|
||||||
|
|
||||||
|
#### Example configuration
|
||||||
|
|
||||||
|
In the example below you can find a `multibackup` configuration file to backup a productional [LiveConfig](http://www.liveconfig.com/) instance.
|
||||||
|
|
||||||
|
`vi ~/.multibackup.conf`
|
||||||
|
|
||||||
|
# Timestamp format, used in the backup target filename
|
||||||
|
timestamp=$(date +%Y%m%d)
|
||||||
|
|
||||||
|
# Destination where you want to store your backups
|
||||||
|
backup_destination="/var/backups"
|
||||||
|
|
||||||
|
# Folders to backup
|
||||||
|
folders_to_backup=(
|
||||||
|
"/etc"
|
||||||
|
"/var/mail"
|
||||||
|
"/var/www"
|
||||||
|
"/var/lib/mysql"
|
||||||
|
"/var/spool/cron"
|
||||||
|
"/var/lib/liveconfig"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Files and folders that are excluded in the tar command
|
||||||
|
tar_excludes=(
|
||||||
|
"nginx-php-fcgi.sock"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Additional tar Options
|
||||||
|
tar_options=()
|
||||||
|
|
||||||
|
# How long to you want to keep your backups (in days)
|
||||||
|
backup_retention="+7"
|
||||||
|
|
||||||
|
# Commands that are executed before the backup started
|
||||||
|
# (We have to make sure the liveconfig process is not running)
|
||||||
|
# (otherwise the databases changes while we try to save it)
|
||||||
|
pre_commands=(
|
||||||
|
"service liveconfig stop"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Commands that are executed after the backup is completed
|
||||||
|
# (To restart the liveconfig process again, once the backup is completed)
|
||||||
|
post_commands=(
|
||||||
|
"service liveconfig start"
|
||||||
|
)
|
||||||
|
|
||||||
|
#### Cronjob setup
|
||||||
|
|
||||||
|
To make sure the backup is executed automatically and recurring, we're going to add a simple cronjob:
|
||||||
|
|
||||||
|
`vi /etc/cron.d/backup-liveconfig`
|
||||||
|
|
||||||
|
#
|
||||||
|
# cronjob to backup LiveConfig, daily at 5:00 am
|
||||||
|
#
|
||||||
|
|
||||||
|
0 5 * * * root /usr/local/bin/multibackup &>/dev/null
|
||||||
|
|
||||||
|
#### CREDITS
|
||||||
|
This Backup Script is a fork of https://github.com/frdmn/tar-multibackup
|
178
multibackup
Normal file
178
multibackup
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
[[ -n "${DEBUG}" ]] && set -x
|
||||||
|
|
||||||
|
###
|
||||||
|
# Configuration
|
||||||
|
###
|
||||||
|
|
||||||
|
# Use "~/.multibackup" as default config, if $CONFIG is not specified
|
||||||
|
CONFIG="${CONFIG:-${HOME}/.multibackup.conf}"
|
||||||
|
|
||||||
|
###
|
||||||
|
# Functions
|
||||||
|
###
|
||||||
|
|
||||||
|
# Color helpers
|
||||||
|
color_red=$(tput setaf 1)
|
||||||
|
color_yellow=$(tput setaf 3)
|
||||||
|
color_green=$(tput setaf 2)
|
||||||
|
color_reset=$(tput sgr0)
|
||||||
|
|
||||||
|
# Logging prefix helper
|
||||||
|
prefix(){
|
||||||
|
# Check if placeholders variables are given
|
||||||
|
if [[ -n "${current_action}" && -n "${current_task}" && -n "${total_tasks}" ]]; then
|
||||||
|
# Return prefix
|
||||||
|
echo "[${current_action}] [${current_task}/${total_tasks}] "
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logging helpers
|
||||||
|
debug() {
|
||||||
|
echo "$(prefix)[DEBUG] $@ " 1>&2
|
||||||
|
}
|
||||||
|
|
||||||
|
success() {
|
||||||
|
echo "$(prefix)${color_green}[SUCCESS]${color_reset} $@" 1>&2
|
||||||
|
}
|
||||||
|
|
||||||
|
info() {
|
||||||
|
echo "$(prefix)${color_yellow}[INFO]${color_reset} $@" 1>&2
|
||||||
|
}
|
||||||
|
|
||||||
|
error() {
|
||||||
|
echo "$(prefix)${color_red}[ERROR]${color_reset} $@" 1>&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Strip all redundant slashes in file paths
|
||||||
|
strip_duplicate_slashes_in_path(){
|
||||||
|
# Backup current shopt options
|
||||||
|
shoptBackup=$(shopt -p)
|
||||||
|
# Set extented globbing
|
||||||
|
shopt -s extglob
|
||||||
|
# Substitute input (turn multiple slashes into single one) and return
|
||||||
|
echo "${@//+(\/)//}"
|
||||||
|
# Restore shopt
|
||||||
|
eval "$oldShoptOptions" &> /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Replace all slashes with dashes
|
||||||
|
replace_slash_with_dash(){
|
||||||
|
input="${@////-}" # replace all slashes with dashes
|
||||||
|
input="${input/#-/}" # remove possible starting dash
|
||||||
|
output="${input/%-/}" # as well as possible trailing dash
|
||||||
|
echo "${output}"
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
# Logic
|
||||||
|
###
|
||||||
|
|
||||||
|
# Check for config file then read and source
|
||||||
|
if [[ -f "${CONFIG}" ]]; then
|
||||||
|
. "${CONFIG}"
|
||||||
|
else
|
||||||
|
error "Couldn't find configuration file \"${CONFIG}\""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Iterate through tar_excludes to create a "--exclude=XXX" combination string
|
||||||
|
tar_exclude_parameters=()
|
||||||
|
if [[ "${#tar_excludes[@]}" -ne 0 ]]; then
|
||||||
|
# Run each pre command
|
||||||
|
for parameter in "${tar_excludes[@]}"; do
|
||||||
|
tar_exclude_parameters+=( "--exclude=${parameter}" )
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set prefix variables for pre-commands
|
||||||
|
current_action="pre-command"
|
||||||
|
current_task=1
|
||||||
|
total_tasks="${#pre_commands[@]}"
|
||||||
|
|
||||||
|
# Iterate through pre_commnads
|
||||||
|
if [[ "${#pre_commands[@]}" -ne 0 ]]; then
|
||||||
|
info "Found pre commands..."
|
||||||
|
# Run each pre command
|
||||||
|
for pre_command in "${pre_commands[@]}"; do
|
||||||
|
info "Running \"${pre_command}\":"
|
||||||
|
eval "${pre_command}"
|
||||||
|
# Check if pre command ran successfully
|
||||||
|
if [[ $? -eq 0 ]]; then
|
||||||
|
success "Pre command \"${pre_command}\" successfully completed!"
|
||||||
|
else
|
||||||
|
error "Pre command \"${pre_command}\" failed..."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set prefix variables for backup
|
||||||
|
current_action="backup"
|
||||||
|
current_task=1
|
||||||
|
total_tasks="${#folders_to_backup[@]}"
|
||||||
|
|
||||||
|
# Iterate through "$folders_to_backup"
|
||||||
|
for folder_to_backup in "${folders_to_backup[@]}"; do
|
||||||
|
# Check if folder exists
|
||||||
|
debug "Check if source folder \"${folder_to_backup}\" exists..."
|
||||||
|
if [[ -d "${folder_to_backup}" ]]; then
|
||||||
|
# Exist => continue
|
||||||
|
info "Source folder \"${folder_to_backup}\" exists!"
|
||||||
|
# Make sure backup destination exists
|
||||||
|
backup_basename=$(replace_slash_with_dash "${folder_to_backup}")
|
||||||
|
absolute_backup_destination=$(strip_duplicate_slashes_in_path "${backup_destination}/${backup_basename}")
|
||||||
|
if [[ ! -d "${absolute_backup_destination}" ]]; then
|
||||||
|
info "Backup destination folder \"${absolute_backup_destination}\" doesn't exist. Creating..."
|
||||||
|
mkdir -p "${absolute_backup_destination}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if backup already exists (to make sure)
|
||||||
|
if [[ -f "${absolute_backup_destination}/${timestamp}.tar.gz" ]]; then
|
||||||
|
error "Backup \"${absolute_backup_destination}/${timestamp}.tar.gz\" already exists. Skipping..."
|
||||||
|
else
|
||||||
|
# Start backup
|
||||||
|
info "Starting backup \"${absolute_backup_destination}/${timestamp}.tar.gz\""
|
||||||
|
tar ${tar_options} -czf "${absolute_backup_destination}/${timestamp}.tar.gz" -P "${folder_to_backup}" "${tar_exclude_parameters[@]}"
|
||||||
|
if [[ $? -eq 0 ]]; then
|
||||||
|
success "Backup \"${absolute_backup_destination}/${timestamp}.tar.gz\" successfully completed!"
|
||||||
|
else
|
||||||
|
error "Backup \"${absolute_backup_destination}/${timestamp}.tar.gz\" failed..."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove old backups
|
||||||
|
if [[ ! -z "${backup_retention}" ]]; then
|
||||||
|
find "${absolute_backup_destination}/" -maxdepth 1 -mtime "${backup_retention}" -type f -exec rm -rf {} \;
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Doesn't exist => skip
|
||||||
|
error "Folder \"${folder_to_backup}\" doesn't exist. Skipping..."
|
||||||
|
fi
|
||||||
|
# Increment $current_task variable
|
||||||
|
current_task=$((current_task+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
# Set prefix variables for pre-commands
|
||||||
|
current_action="post-command"
|
||||||
|
current_task=1
|
||||||
|
total_tasks="${#post_commands[@]}"
|
||||||
|
|
||||||
|
# Iterate through post_commnads
|
||||||
|
if [[ "${#post_commands[@]}" -ne 0 ]]; then
|
||||||
|
info "Found post commands..."
|
||||||
|
# Run each post command
|
||||||
|
for post_command in "${post_commands[@]}"; do
|
||||||
|
info "Running \"${post_command}\":"
|
||||||
|
eval "${post_command}"
|
||||||
|
# Check if post command ran successfully
|
||||||
|
if [[ $? -eq 0 ]]; then
|
||||||
|
success "Post command \"${post_command}\" successfully completed!"
|
||||||
|
else
|
||||||
|
error "Post command \"${post_command}\" failed..."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Return exit code
|
||||||
|
exit 0
|
26
multibackup.conf
Normal file
26
multibackup.conf
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Timestamp format, used in the backup target filename
|
||||||
|
timestamp=$(date +%Y%m%d)
|
||||||
|
|
||||||
|
# Destination where you want to store your backups
|
||||||
|
backup_destination="/var/backups"
|
||||||
|
|
||||||
|
# Folders to backup
|
||||||
|
folders_to_backup=(
|
||||||
|
"/var/www"
|
||||||
|
"/var/lib/mysql"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Files and folders that are excluded in the tar command
|
||||||
|
tar_excludes=()
|
||||||
|
|
||||||
|
# Additional tar Options
|
||||||
|
tar_options=()
|
||||||
|
|
||||||
|
# How long to you want to keep your backups (in days)
|
||||||
|
backup_retention="+7"
|
||||||
|
|
||||||
|
# Commands that are executed before the backup started
|
||||||
|
pre_commands=()
|
||||||
|
|
||||||
|
# Commands that are executed after the backup is completed
|
||||||
|
post_commands=()
|
Reference in New Issue
Block a user