Skip to content

Commit

Permalink
[Release] Version 1.2
Browse files Browse the repository at this point in the history
* develop:
  Added support for encrypted repositories
  Added .gitignore file to ignore local config
  Added support for NOTIFY_MESSAGE with Pushover.
  Added Pushover.net support as a notification method.
  • Loading branch information
Nuxij committed Feb 15, 2015
2 parents 331477d + 8e99d14 commit df79e43
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 60 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
backupld.conf.local
backupld.log
177 changes: 125 additions & 52 deletions backupld
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
# Start Date: 12/03/14

# Dependencies / Setup
set -o pipefail
. cpfb
TODAY_DATE="$(date +%Y%m%d)"
FAIL_COUNT=0
LOG="$(mktemp /tmp/backupld_XXXXX)"
parseConfig "$1" >> "$LOG" || let FAIL_COUNT+=1
parseConfig "$1" || let FAIL_COUNT+=1

# Check backup_name specials
if [[ "$BACKUP_NAME" == "date" ]]; then
Expand All @@ -16,98 +17,124 @@ fi

# Logic
createBackup() {
echo "--- [Create] Backup for $1::$2" >> "$LOG"
if $(attic create --stats "$BACKUP_HOST:$1.attic::$BACKUP_NAME" "$2" --exclude .forever --exclude tmp >> "$LOG" 2>&1); then
echo "--- [Create] Completed successfully" >> "$LOG"
echo "--- [Create] Backup for $1::$2" | printMessage
attic create -v --stats "$BACKUP_HOST:$1.attic::$BACKUP_NAME" "$2" --exclude .forever --exclude tmp 2>&1 | printMessage
exitCode=$?
if [[ $exitCode -eq 0 ]]; then
echo "--- [Create] Completed successfully" | printMessage
return 0
else
echo "--- [Create] Completed unsuccessfully" >> "$LOG"
echo "--- [Create] Completed unsuccessfully" | printMessage
let FAIL_COUNT+=1
return 1
fi
}

pruneBackup() {
echo "--- [Prune] Backup for $1::$2" >> "$LOG"
echo "--- [Prune] Backup for $1::$2" | printMessage
local keeps=
local hourly=
local daily=
local weekly=
local monthly=
[[ ${PRUNE_HOURLY[default]} ]] && hourly="-H ${PRUNE_HOURLY[default]}"
[[ ${PRUNE_HOURLY[$1]} ]] && hourly="-H ${PRUNE_HOURLY[$1]}"
[[ ${hourly: -1} -eq 0 ]] && hourly=
[[ "${PRUNE_HOURLY[default]}" ]] && hourly="-H ${PRUNE_HOURLY[default]}"
[[ "${PRUNE_HOURLY[$1]}" ]] && hourly="-H ${PRUNE_HOURLY[$1]}"
[[ "${hourly: -1}" -eq 0 ]] && hourly=
keeps="$hourly"
[[ ${PRUNE_DAILY[default]} ]] && daily="-d ${PRUNE_DAILY[default]}"
[[ ${PRUNE_DAILY[$1]} ]] && daily="-d ${PRUNE_DAILY[$1]}"
[[ ${daily: -1} -eq 0 ]] && daily=
[[ "${PRUNE_DAILY[default]}" ]] && daily="-d ${PRUNE_DAILY[default]}"
[[ "${PRUNE_DAILY[$1]}" ]] && daily="-d ${PRUNE_DAILY[$1]}"
[[ "${daily: -1}" -eq 0 ]] && daily=
keeps="$keeps $daily"
[[ ${PRUNE_WEEKLY[default]} ]] && weekly="-w ${PRUNE_WEEKLY[default]}"
[[ ${PRUNE_WEEKLY[$1]} ]] && weekly="-w ${PRUNE_WEEKLY[$1]}"
[[ ${weekly: -1} -eq 0 ]] && weekly=
[[ "${PRUNE_WEEKLY[default]}" ]] && weekly="-w ${PRUNE_WEEKLY[default]}"
[[ "${PRUNE_WEEKLY[$1]}" ]] && weekly="-w ${PRUNE_WEEKLY[$1]}"
[[ "${weekly: -1}" -eq 0 ]] && weekly=
keeps="$keeps $weekly"
[[ ${PRUNE_MONTHLY[default]} ]] && monthly="-m ${PRUNE_MONTHLY[default]}"
[[ ${PRUNE_MONTHLY[$1]} ]] && monthly="-m ${PRUNE_MONTHLY[$1]}"
[[ ${monthly: -1} -eq 0 ]] && monthly=
[[ "${PRUNE_MONTHLY[default]}" ]] && monthly="-m ${PRUNE_MONTHLY[default]}"
[[ "${PRUNE_MONTHLY[$1]}" ]] && monthly="-m ${PRUNE_MONTHLY[$1]}"
[[ "${monthly: -1}" -eq 0 ]] && monthly=
keeps="$keeps $monthly"
[[ ${PRUNE_YEARLY[default]} ]] && yearly="-y ${PRUNE_YEARLY[default]}"
[[ ${PRUNE_YEARLY[$1]} ]] && yearly="-y ${PRUNE_YEARLY[$1]}"
[[ ${yearly: -1} -eq 0 ]] && yearly=
[[ "${PRUNE_YEARLY[default]}" ]] && yearly="-y ${PRUNE_YEARLY[default]}"
[[ "${PRUNE_YEARLY[$1]}" ]] && yearly="-y ${PRUNE_YEARLY[$1]}"
[[ "${yearly: -1}" -eq 0 ]] && yearly=
keeps="$keeps $yearly"
if $(attic prune -v "$BACKUP_HOST:$1.attic" $keeps >> "$LOG" 2>&1); then
echo "--- [Prune] Completed successfully" >> "$LOG"
attic prune --stats "$BACKUP_HOST:$1.attic" $keeps 2>&1 | printMessage
exitCode=$?
if [[ $exitCode -eq 0 ]]; then
echo "--- [Prune] Completed successfully" | printMessage
return 0
else
echo "--- [Prune] Completed unsuccessfully" >> "$LOG"
echo "--- [Prune] Completed unsuccessfully" | printMessage
let FAIL_COUNT+=1
return 1
fi
}

checkBackup() {
echo "--- [Check] Backup for for $1::$2" >> "$LOG"
if $(attic check -v "$BACKUP_HOST:$1.attic" >> "$LOG" 2>&1); then
echo "--- [Check] Completed successfully" >> "$LOG"
echo "--- [Check $(date +%A)] Backup for $1::$2" | printMessage
attic check -v "$BACKUP_HOST:$1.attic" 2>&1 | printMessage
exitCode=$?
if [[ $exitCode -eq 0 ]]; then
echo "--- [Check] Completed successfully" | printMessage
return 0
else
echo "--- [Check] Completed unsuccessfully" >> "$LOG"
echo "--- [Check] Completed unsuccessfully" | printMessage
let FAIL_COUNT+=1
return 1
fi
}

checkEncryption() {
if [[ -n "$1" ]]; then
export ATTIC_PASSPHRASE="$1"
return 0
fi
return 1
}

runBackups() {
local failed=0
echo "#### backupld - Starting ####" >> "$LOG"
echo "#### backupld - Starting ####" | printMessage
for dir in "${!LOCAL_BACKUP_DIRS[@]}"; do
if createBackup "$dir" "${LOCAL_BACKUP_DIRS[$dir]}"; then
pruneBackup "$dir" "${LOCAL_BACKUP_DIRS[$dir]}"
local dirPath="$(echo ${LOCAL_BACKUP_DIRS[$dir]} | awk -F';' '{print $1}')"
if checkEncryption "$(echo ${LOCAL_BACKUP_DIRS[$dir]} | awk -F';' '{print $2}')"; then
echo "--- ...enabled encryption..." | printMessage
elif [[ -n "$ATTIC_PASSPHRASE" ]]; then
export ATTIC_PASSPHRASE=
echo "--- ...disabled encryption..." | printMessage
fi
if createBackup "$dir" "$dirPath"; then
pruneBackup "$dir" "$dirPath"
if [[ $(date +%u) -eq $BACKUP_CHECK_DAY ]]; then
checkBackup "$dir" "$dirPath"
fi
fi
done
if [[ $(date +%u) -eq $BACKUP_CHECK_DAY ]]; then
echo "--- [Check] It's $(date +%A)! Verifying consistency..." >> "$LOG"
for dir in "${!LOCAL_BACKUP_DIRS[@]}"; do
checkBackup "$dir" "${LOCAL_BACKUP_DIRS[$dir]}"
done
fi
if [[ "$FAIL_COUNT" -gt 0 ]]; then
echo "#### backupld - Unuccessful ####" >> "$LOG"
echo "#### backupld - Unuccessful ####" | printMessage
else
echo "#### backupld - Successful ####" >> "$LOG"
echo "#### backupld - Successful ####" | printMessage
fi
for user in "${NOTIFY_USERS[@]}"; do
notifyUser "$(echo $user | cut -d';' -f1)" "$(echo $user | cut -d';' -f2)"
done
cp -f "$LOG" "/var/log/backupld-$TODAY_DATE-$FAIL_COUNT.log"
rm -rf "$LOG"

notifyUsers

# Cleanup
return $FAIL_COUNT
}

notifyUser() {
notifyUsers() {
local user
if [[ "$NOTIFY_TYPE" == "email" ]]; then
notifyByEmail "$1" "$2"
for user in "${NOTIFY_USERS[@]}"; do
notifyByEmail "$(echo $user | cut -d';' -f1)" "$(echo $user | cut -d';' -f2)"
[[ $? -ne 0 ]] && let FAIL_COUNT+=1 && return 1
done
elif [[ "$NOTIFY_TYPE" == "pushover" ]]; then
notifyByPushover
[[ $? -ne 0 ]] && let FAIL_COUNT+=1 && return 1
elif [[ "$NOTIFY_TYPE" == "file" ]]; then
notifyByFile "$1" "$2"
for user in "${NOTIFY_USERS[@]}"; do
notifyByFile "$(echo $user | cut -d';' -f1)" "$(echo $user | cut -d';' -f2)"
[[ $? -ne 0 ]] && let FAIL_COUNT+=1 && return 1
done
fi
}

Expand Down Expand Up @@ -137,8 +164,8 @@ notifyByEmail() {
'https://mandrillapp.com/api/1.0/messages/send.json'
)
if [[ ! $output =~ \"status\"\:\"queued\" ]]; then
echo "ERROR: Mandrill notifcation failed for: $1 <$2>." >> $LOG
echo "ERROR: $output" >> $LOG
echo "ERROR: Mandrill notifcation failed for: $1 <$2>." | printMessage
echo "ERROR: $output" | printMessage
fi
elif [[ "$NOTIFY_MAILGUN" ]]; then
local output=$(curl -s --user "api:$NOTIFY_MAILGUN" \
Expand All @@ -151,8 +178,8 @@ notifyByEmail() {
-F o:tag="backupld"
)
if [[ ! $output =~ \"message\"\:\ \"Queued\.\ Thank\ you\.\" ]]; then
echo "ERROR: Mailgun notifcation failed for: $1 <$2>." >> $LOG
echo "ERROR: $output" >> $LOG
echo "ERROR: Mailgun notifcation failed for: $1 <$2>." | printMessage
echo "ERROR: $output" | printMessage
let FAIL_COUNT+=1
fi
else
Expand All @@ -161,6 +188,52 @@ notifyByEmail() {
fi
}

notifyByPushover() {
local message="$FAIL_COUNT errors occured"
[[ "$NOTIFY_MESSAGE" ]] && message="$(messageMacrofier $NOTIFY_MESSAGE)"
if [[ "$NOTIFY_PUSHOVER_API_KEY" ]]; then
local apiKey="$NOTIFY_PUSHOVER_API_KEY"
if [[ "$NOTIFY_PUSHOVER_USER_KEY" ]]; then
local userKey="$NOTIFY_PUSHOVER_USER_KEY"
local output=$(curl -s \
https://api.pushover.net/1/messages.json \
-F "token=$apiKey" \
-F "user=$userKey" \
-F "title=[backupld] Complete" \
-F "message=$message" \
)
if [[ ! $output =~ \"status\"\:\ ?1 ]]; then
echo "ERROR: Pushover notifcation failed." | printMessage
echo "ERROR: $output" | printMessage
let FAIL_COUNT+=1
fi
else
echo "ERROR: No Pushover user key" | printMessage
let FAIL_COUNT+=1
fi
else
echo "ERROR: No Pushover API key" | printMessage
let FAIL_COUNT+=1
fi
}

notifyByFile() {
if [[ "$2" ]]; then
cp -f "$LOG" "$2"
rm -rf "$LOG"
fi
}

printMessage() {
local message
while read message; do
if [[ "$NOTIFY_ECHO" == "true" ]]; then
echo "$message"
fi
echo "$message" >> "$LOG"
done
}

messageMacrofier() {
echo "$(echo $@ | m4 \
-D name="$BACKUP_NAME" \
Expand Down
39 changes: 31 additions & 8 deletions backupld.conf
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@
# The day of the week to run validity checks
# Uses $(date +%u) so numbers are (1..7); 1 is Monday
CHECK_DAY = 7

# What do we care about?
# In the format: repoName = /directory/to/backup
#
# Support for encrypted repos is available, just append the passphrase:
# repoName = /directory/to/backup;passphrase123
#
==LOCAL_BACKUP_DIRS
vhosts = /var/www/vhosts
git = /home/git
cron = /var/spool/cron
cron = /var/spool/cron;CronSaf3ty

# How often do we want to prune?
# (How many to keep on each timescale)
Expand All @@ -30,39 +33,59 @@
#
==PRUNE_DAILY
default=7

==PRUNE_WEEKLY
default=4

==PRUNE_MONTHLY
default=6

# How do we want to send notifications?
# Supported methods are 'email', 'pushover' or 'file'
#
# 'email' is the only supported so far
# This uses Mandrill or Mailgun, set your keys as so:
# Email ---
# Set type: TYPE = email
# We use Mandrill or Mailgun, set your keys as so:
# MANDIRLL = <key here> or
# MAILGUN = <key here>
# with Mailgun, you also need to set the name of the api domain:
# MAILGUN_API_DOMAIN = example.com
#
#
# FROM_DOMAIN is the domain of the sender: example.com
# MESSAGE is the body of the email in text (no HTML)
# EMAIL_SUBJECT is the subject of the email (amazing!)
#
# Pushover ---
# Set type: TYPE = pushover
# Using Pushover.net, set your keys as so:
# PUSHOVER_API_KEY = <api key hare>
# PUSHOVER_USER_KEY = <user key here>
#
# Pushover supports the MESSAGE option too
# MESSAGE = <body of notification>
#
# File ---
# Set type: TYPE = file
# The log file will be copied per user,
# specify location for each one with NOTIFY_USERS.
# To echo to the console as well, set
# ECHO = true
#
# Extra ---
# Both the message and subject support some macros:
# 'name' will be changed to the name of the archive
# 'date' is changed to the date from above: YYYYMMDD
# 'fail_count' is changed to the failure count of the backups
#
::NOTIFY_
TYPE = email
MANDRILL = sajnDCSsSDCnkiaScERPO<
MANDRILL = sajnDCSsSDCnkiaScERPOJ
FROM_DOMAIN = example.com
MESSAGE = Completed with fail_count errors.
EMAIL_SUBJECT = [Daily name] Failure Count fail_count

# Who should we tell?
# In the format: Recipient Name;[email protected]
# Or: Recipient Name;/path/to/file
--NOTIFY_USERS
Joe Eaves;[email protected]

0 comments on commit df79e43

Please sign in to comment.