backupDailyDirPattern="^20[0-9]{2}-[0-9]{2}-[0-9]{2}$backupDailySuffix$" backupArchiveDirPattern="^20[0-9]{2}-[0-9]{2}-[0-9]{2}$backupArchiveSuffix$" # Generates a backup destination path; uses $backupFirst for the first backup of the day, $appTime otherwise. # [$1] (path): explicit destination path; returned unchanged if provided. function backupPathGenerate() { local path="$1" if [[ -z "$path" ]]; then path="$backupDailyPath/$appDate/$backupFirstDir" [[ -d "$path" ]] && path="$backupDailyPath/$appDate/$appTime" fi printf '%s' "$path" } # Creates a file backup archive for a site. # $1 (domain): site domain name. # $2 (file): target archive file path. function backupSiteFiles() { local domain domain=$(domainPrepare "$1") domainCheck "$domain" || return 1 local file="$2" [[ -n "$file" ]] || { appError "Target file not specified"; return 1; } local compressProgram="" if [[ -n "${pigzThreads:-}" ]] && command -v pigz &>/dev/null; then compressProgram="pigz -p $pigzThreads" fi archiveCreate "$vhostsPath/$domain" "$file" "$compressProgram" } # Creates a database backup for a site. # $1 (domain): site domain name. # $2 (file): target database backup file path. function backupSiteDatabase() { local domain domain=$(domainPrepare "$1") domainCheck "$domain" || return 1 local file="$2" [[ -n "$file" ]] || { appError "Target file not specified"; return 1; } local databaseName databaseUser databasePass databaseName=$(siteConfigGet "$domain" "databaseName") [[ -n "$databaseName" ]] || { appError "databaseName not found or empty"; return 1; } databaseUser=$(siteConfigGet "$domain" "databaseUser") [[ -n "$databaseUser" ]] || { appError "databaseUser not found or empty"; return 1; } databasePass=$(siteConfigGet "$domain" "databasePass") [[ -n "$databasePass" ]] || { appError "databasePass not found or empty"; return 1; } mariadbMasterExport "$databaseUser" "$databasePass" "$databaseName" "$file" } # Creates a full backup for a site: files, database, and OLS vhost config. # $1 (domain): site domain name. # [$2] (path): destination directory; auto-generated if omitted. # [$3] (type): backup type: zip, tar, or archive (defaults to $backupType). function backupSite() { local domain domain=$(domainPrepare "$1") domainCheck "$domain" || return 1 local path path=$(backupPathGenerate "$2") local type="${3:-$backupType}" case "$type" in zip) backupSiteFiles "$domain" "$path/$domain.zip" || return 1 backupSiteDatabase "$domain" "$path/$domain.sql.zip" || return 1 ;; tar|archive) backupSiteFiles "$domain" "$path/$domain.tar.gz" || return 1 backupSiteDatabase "$domain" "$path/$domain.sql.tar.gz" || return 1 ;; *) appError "Unknown type: $type" return 1 ;; esac cp -f -- "$openlitespeedVhostsPath/$domain.conf" "$path/$domain.conf" || { appError "Failed to copy vhost config: $domain" return 1 } } # Syncs a local path to a remote server using rsync. # $1 (sourcePath): local path to sync. function storagePathSyncRsync() { local sourcePath="$1" [[ -n "$sourcePath" ]] || { appError "Source path not specified"; return 1; } rsync -aH --delete --password-file="$rsyncPassFile" "$sourcePath" rsync://"$rsyncUri$rsyncPath" } # Syncs a local path to a remote server over SSH using rsync. # $1 (sourcePath): local path to sync. function storagePathSyncSSH() { local sourcePath="$1" [[ -n "$sourcePath" ]] || { appError "Source path not specified"; return 1; } rsync -aH --delete -e "ssh -i $sshKeyFile" "$sourcePath" "$sshUser@$sshHost:$sshPath" } function storageBackupRemove() { local backup error backup="$1" [[ -n "$backup" ]] || { appError "Backup not specified"; return 1; } case "$storageType" in rsync) if ! runError error rsyncDirectoryClean "$rsyncPath/$backup"; then appError "$error" elif ! runError error ftpDirectoryDelete "/$backup"; then appError "$error" fi ;; ssh) if ! runError error sshDirectoryDelete "/$backup"; then appError "$error" return 1 fi ;; *) appError "Unknown storageType: $storageType" return 1 ;; esac }