From e79d26435b2719ef7cd0fa6e11256b8ae4f8bd8f Mon Sep 17 00:00:00 2001 From: Charlie Silverman Date: Sun, 18 Oct 2026 12:26:09 -0700 Subject: [PATCH] Update to version 1.6 Added logging, error handline, command line argument names, and command line help. Overall script cleanup. --- AppBackup-restic.sh | 352 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 352 insertions(+) create mode 100644 AppBackup-restic.sh diff --git a/AppBackup-restic.sh b/AppBackup-restic.sh new file mode 100644 index 0000000..1d3628c --- /dev/null +++ b/AppBackup-restic.sh @@ -0,0 +1,352 @@ +#!/bin/bash +# +# Script Name: AppBackup-restic.sh +# Description: +# Creates a backup of a web application and optionally its MySQL database. +# The script archives the application home directory and uploads the backup +# either to a remote SFTP server or to a Backblaze B2 repository using Restic, +# depending on the host on which it is executed. +# +# Usage: +# AppBackup-restic.sh --appname --appuser [--apppassword ] +# +# Author: Charlie Silverman +# Version: 1.6 +# +# Revision History: +# 1.0 - Initial version. +# 1.1 - Added logging to file. +# 1.2 - Added strict error handling, input validation, and FQDN support. +# 1.3 - Added trap-based error logging and improved operational visibility. +# 1.4 - Added application-specific log files, interrupt handling, +# and enhanced logging. +# 1.5 - Added command-line help. +# 1.6 - Replaced positional parameters with named command-line options +# and added support for short/long option formats. +# + +set -o errexit +set -o nounset +set -o pipefail + +#------------------------------------------------------------------------------ +# Help Function +#------------------------------------------------------------------------------ + +show_help() { + +cat << EOF + +AppBackup-restic.sh v1.6 + +DESCRIPTION + Creates a backup of a web application's files and optionally its + MySQL database. The backup is uploaded either via SFTP or Restic, + depending on the host. + +USAGE + + AppBackup-restic.sh --appname --appuser [--apppassword ] + +OPTIONS + + -a, --appname + Name of the application and MySQL database. + Required. + + -u, --appuser + Linux account that owns the application files. + Required. + + -p, --apppassword + MySQL password and SFTP password (if applicable). + Optional. + + -h, --help + Display this help and exit. + +EXAMPLES + + AppBackup-restic.sh \ + --appname KISNetManager \ + --appuser kisuser \ + --apppassword MySecurePassword + + AppBackup-restic.sh \ + -a CustomerPortal \ + -u portaluser + +LOG FILE + + /tmp/AppBackup-.log + +AUTHOR + + Charlie Silverman + +VERSION + + 1.6 + +EOF + +} + +#------------------------------------------------------------------------------ +# Process Command Line Arguments +#------------------------------------------------------------------------------ + +AppName="" +AppUser="" +AppPassword="" + +while [[ $# -gt 0 ]]; do + + case "$1" in + + -a|--appname) + AppName="$2" + shift 2 + ;; + + --appname=*) + AppName="${1#*=}" + shift + ;; + + -u|--appuser) + AppUser="$2" + shift 2 + ;; + + --appuser=*) + AppUser="${1#*=}" + shift + ;; + + -p|--apppassword) + AppPassword="$2" + shift 2 + ;; + + --apppassword=*) + AppPassword="${1#*=}" + shift + ;; + + -h|--help) + show_help + exit 0 + ;; + + *) + echo "ERROR: Unknown option '$1'" + echo + show_help + exit 1 + ;; + + esac + +done + +#------------------------------------------------------------------------------ +# Validate Required Parameters +#------------------------------------------------------------------------------ + +if [[ -z "$AppName" || -z "$AppUser" ]]; then + echo "ERROR: --appname and --appuser are required." + echo + show_help + exit 1 +fi + +#------------------------------------------------------------------------------ +# Runtime Variables +#------------------------------------------------------------------------------ + +DATE=$(date "+%Y%m%d_%H%M%S") +HOSTNAME_FQDN="$(hostname -f)" + +SAFE_APPNAME=$(echo "$AppName" | tr -cs '[:alnum:]_-' '_') + +LOGFILE="/tmp/AppBackup-${SAFE_APPNAME}.log" + +#------------------------------------------------------------------------------ +# Logging Function +#------------------------------------------------------------------------------ + +log() { + echo "$(date '+%Y-%m-%d %H:%M:%S') [$$] $1" | tee -a "$LOGFILE" +} + +#------------------------------------------------------------------------------ +# Error Handling +#------------------------------------------------------------------------------ + +error_handler() { + + local exit_code=$? + local line_number=$1 + + log "ERROR: Backup failed on line ${line_number} with exit code ${exit_code}" + + exit "${exit_code}" +} + +interrupt_handler() { + + log "ERROR: Backup interrupted by signal" + + exit 1 +} + +trap 'error_handler $LINENO' ERR +trap interrupt_handler SIGINT SIGTERM + +#------------------------------------------------------------------------------ +# Startup Logging +#------------------------------------------------------------------------------ + +log "=================================================================" +log "Starting backup job" +log "Application: $AppName" +log "Application User: $AppUser" +log "Host: $HOSTNAME_FQDN" +log "Log File: $LOGFILE" +log "=================================================================" + +#------------------------------------------------------------------------------ +# Restic Repository Configuration +#------------------------------------------------------------------------------ + +export RESTIC_REPOSITORY="s3:https://s3.us-west-004.backblazeb2.com/ackitsbucket/docker" +export RESTIC_PASSWORD_FILE="/root/.restic-password" + +#------------------------------------------------------------------------------ +# Host Specific Configuration +#------------------------------------------------------------------------------ + +HostPrefix="" + +if [[ "$HOSTNAME_FQDN" == "ackitserver.ackcentuate.com" ]]; then + + if [[ "$AppName" == "KISNetManager" ]]; then + HostPrefix="dev-" + fi + +fi + +ArchiveFile="${AppName}-${DATE}.tar.bz2" + +#------------------------------------------------------------------------------ +# Prepare Backup Workspace +#------------------------------------------------------------------------------ + +log "Changing to backup directory" + +cd /home/Backups + +#------------------------------------------------------------------------------ +# Database Backup +#------------------------------------------------------------------------------ + +if [[ -n "$AppPassword" ]]; then + + log "Creating MySQL database backup" + + mkdir -p "/home/${AppUser}/SQLBackup" + + mysqldump \ + -u "$AppUser" \ + --password="$AppPassword" \ + "$AppName" \ + > "/home/${AppUser}/SQLBackup/${AppName}.sqldump" + + log "MySQL dump completed successfully" + +else + + log "Database password not supplied. Skipping MySQL backup." + +fi + +#------------------------------------------------------------------------------ +# Remove Previous Backup Archives +#------------------------------------------------------------------------------ + +log "Removing previous backup archives" + +rm -f /home/Backups/"${AppName}"*.tar.bz* +rm -f /home/Backups/"${HostPrefix}${AppName}"*.tar.bz* + +#------------------------------------------------------------------------------ +# Create Archive +#------------------------------------------------------------------------------ + +log "Creating archive ${HostPrefix}${ArchiveFile}" + +tar cjf \ + "/home/Backups/${HostPrefix}${ArchiveFile}" \ + "/home/${AppUser}/" + +log "Archive created successfully" + +#------------------------------------------------------------------------------ +# Upload Backup +#------------------------------------------------------------------------------ + +if [[ "$HOSTNAME_FQDN" != "ackitserver.ackcentuate.com" ]]; then + + if [[ -z "$AppPassword" ]]; then + log "ERROR: SFTP upload requires --apppassword" + exit 1 + fi + + log "Uploading archive via SFTP" + + lftp "sftp://${AppUser}:${AppPassword}@webbuilder.ackcentuate.com" -e \ + "cd /home/Backups; put /home/Backups/${HostPrefix}${ArchiveFile}; bye" + + log "SFTP upload completed successfully" + +else + + log "Loading Restic environment" + + source /root/.restic-env + + log "Starting Restic backup" + + restic backup "/home/${AppUser}/" \ + --tag apache \ + --tag website \ + --tag "$AppName" \ + --tag "$HOSTNAME_FQDN" \ + >> "$LOGFILE" 2>&1 + + log "Restic backup completed successfully" + +fi + +#------------------------------------------------------------------------------ +# Cleanup +#------------------------------------------------------------------------------ + +if [[ -n "$AppPassword" ]]; then + + log "Removing temporary SQL backup files" + + rm -rf "/home/${AppUser}/SQLBackup" + +fi + +#------------------------------------------------------------------------------ +# Completion +#------------------------------------------------------------------------------ + +log "Backup completed successfully" +log "Application: $AppName" +log "Archive: ${HostPrefix}${ArchiveFile}" +log "Host: $HOSTNAME_FQDN" +log "=================================================================" \ No newline at end of file