From 6b95cb6d7bfcbc8a5fa0dfb925b0c6afe0db6651 Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Sun, 12 Jan 2025 12:15:54 +0100 Subject: [PATCH] Ubdating bin/manual-backup --- bin/manual-backup | 338 ++++++++++++++++++++++------------------------ 1 file changed, 161 insertions(+), 177 deletions(-) diff --git a/bin/manual-backup b/bin/manual-backup index db45507..21c9a7b 100755 --- a/bin/manual-backup +++ b/bin/manual-backup @@ -28,13 +28,15 @@ REMOVE_DATE=$(date -d "${BACKUP_COPIES} days ago" +"%Y-%m-%d") LOGFILE= BACKUP_DIR="${BACKUP_HOSTDIR}/${CDATE}" +MYSQL_ERRORLOG= DO_MYSQL="n" DO_POSTGRES="n" -DO_LDAP="n" +DO_DIR_BACKUP="y" +DO_SYNC="y" declare -a REMOTE_HOSTS=() -declare -a LDAP_ROOT_DNS=() +declare -a DATABASES=() DESCRIPTION=$( cat <<-EOF Macht mal eben so ein Backup. @@ -47,7 +49,7 @@ detect_color #------------------------------------------------------------------------------ usage() { cat <<-EOF - Usage: ${BASE_NAME} [-C COPIES] [-R REMOTE_HOST [-R REMOTE_HOST ...]] [--mysql] [--pgsql] [Common Options] + Usage: ${BASE_NAME} [-C COPIES] [-R REMOTE_HOST [-R REMOTE_HOST ...]] [--mysql] [--pgsql] [-N|--no-dir-backup] [--no-sync] [Common Options] ${BASE_NAME} [-h|--help] ${BASE_NAME} [-V|--version] @@ -63,6 +65,9 @@ usage() { -M|--mysql Perform a backup of the local MySQL/MariaDB database. -P|--pgsql|--postgresql Perform a backup of the local PostrgreSQL database instance. + -N|--no-dir-backup + Don't perform directory backups. + --no-sync Don't sync backups to remote host. EOF } @@ -70,23 +75,11 @@ usage() { #------------------------------------------------------------------------------ TAR() { - local cmd="tar --create --gzip" - if [[ "${VERBOSE}" ]] ; then - cmd+=" --verbose" + local cmd="tar --create --gzip --file $* >/dev/null 2>&1 || true" + if [[ "${VERBOSE}" == "y" ]] ; then + cmd="tar --create --gzip --verbose --file $* 2>&1 | tee -a \"${LOGFILE}\" || true" fi - cmd+=" --file $1" - shift - while [[ "$#" -gt 0 ]] ; do - cmd+=" \"$1\"" - shift - done - if [[ "${VERBOSE}" ]] ; then - cmd+=" 2>&1 | tee -a \"${LOGFILE}\" || true" - else - cmd+=" >/dev/null 2>&1 || true" - fi - - if [[ "${SIMULATE}" ]] ; then + if [[ "${SIMULATE}" == "y" ]] ; then info "Executing: ${cmd}" return fi @@ -123,6 +116,14 @@ eval_my_options() { DO_POSTGRES="y" shift ;; + -N|--no-dir-backup) + DO_DIR_BACKUP="n" + shift + ;; + --no-sync) + DO_SYNC="n" + shift + ;; --) shift break ;; @@ -157,8 +158,8 @@ get_options() { local tmp= local base_dir= - local this_short_options='C:R:MP' - local this_long_options='copies:,remote:,mysql,pgsql,postgresql' + local this_short_options='C:R:MPN' + local this_long_options='copies:,remote:,mysql,pgsql,postgresql,no-dir-backup,no-sync' set +e tmp=$( getopt -o "${STD_SHORT_OPTIONS}${this_short_options}" \ @@ -174,7 +175,7 @@ get_options() { # Note the quotes around `$TEMP': they are essential! eval set -- "${tmp}" eval_common_options "$@" - if [[ "${DEBUG}" ]] ; then + if [[ "${DEBUG}" == 'y' ]] ; then declare -p REMAINING_OPTS declare -p REMAINING_ARGS fi @@ -195,7 +196,7 @@ get_options() { exit 2 fi - if [[ -z "${SIMULATE}" ]] ; then + if [[ "${SIMULATE}" != 'y' ]] ; then LOGFILE="${BACKUP_HOSTDIR}/backup.log" fi } @@ -211,6 +212,7 @@ check_preferences() { local -a tools=('rsync' 'md5sum' 'sha1sum' 'sha256sum') local tool= local folder= + local i=0 for tool in "${tools[@]}" ; do debug "Checking for '${CYAN}${tool}${NORMAL}' ..." @@ -230,6 +232,15 @@ check_preferences() { fi done + debug "Evaluating backup directory ..." + BACKUP_DIR="${BACKUP_HOSTDIR}/${CDATE}.${i}" + while [[ -e "${BACKUP_DIR}" ]] ; do + debug "Path '${CYAN}${BACKUP_DIR}${NORMAL}' is already existing." + i=$(( $i + 1 )) + BACKUP_DIR="${BACKUP_HOSTDIR}/${CDATE}.${i}" + done + info "Backup directory is '${CYAN}${BACKUP_DIR}${NORMAL}'." + if [[ "${all_ok}" != "y" ]] ; then exit 5 fi @@ -241,50 +252,10 @@ dir_backup() { local bdir="${1}" local tarball_base="${2}" - local split_dir="n" - if [[ "$#" -ge 3 ]] ; then - split_dir="$3" - fi - empty_line - debug "Splitting dirs of '${CYAN}/${bdir}${NORMAL}' on dir_backup(): '${CYAN}${split_dir}${NORMAL}'." - - local tarball= - - if [[ "${split_dir}" != "y" ]] ; then - tarball="${BACKUP_DIR}/${tarball_base}.tar.gz" - info "Backup of '${CYAN}/${bdir}${NORMAL}' => '${CYAN}${tarball}${NORMAL}'." - TAR "${tarball}" "${bdir}" - return - fi + local tarball="${BACKUP_DIR}/${tarball_base}.tar.gz" - local -a non_dirs=() - local path= - local bname= - oifs="${IFS}" - IFS=" -" - - for bname in $( ls -1 -A "${bdir}" ) ; do - path="${bdir}/${bname}" - empty_line - debug "Checking path '${CYAN}${path}${NORMAL}' ..." - if [[ -d "${path}" ]] ; then - tarball="${BACKUP_DIR}/${tarball_base}-${bname}.tar.gz" - info "Backup of '${CYAN}${path}${NORMAL}' => '${CYAN}${tarball}${NORMAL}'." - TAR "${tarball}" "${path}" - continue - fi - non_dirs+=( "${path}" ) - done - - IFS="${oifs}" - - if [[ "${#non_dirs[*]}" -ge "1" ]] ; then - tarball="${BACKUP_DIR}/${tarball_base}.non_dirs.tar.gz" - empty_line - info "Backup of non directory paths below '${CYAN}/${bdir}${NORMAL}' => '${CYAN}${tarball}${NORMAL}'." - TAR "${tarball}" "${non_dirs[@]}" - fi + info "Backup of '${CYAN}/${bdir}${NORMAL}' => '${CYAN}${tarball}${NORMAL}'." + TAR "${tarball}" "${bdir}" } @@ -297,18 +268,10 @@ do_dir_backup() { empty_line info "Starting directory backup ..." - MKDIR -p "${BACKUP_DIR}" - cd / dir_backup "etc" "etc" dir_backup "root" "root" - if [[ -d "opt/fbrehm" ]] ; then - dir_backup "opt/fbrehm" "opt-fbrehm" - fi - if [[ -d "var/bind" ]] ; then - dir_backup "var/bind" "var-bind" - fi - dir_backup "var/lib" "var-lib" "y" + dir_backup "var/lib" "var-lib" dir_backup "var/log" "var-log" dir_backup "var/spool/cron" "var-spool-cron" if [[ -d "var/spool/postfix" ]] ; then @@ -318,7 +281,7 @@ do_dir_backup() { dir_backup "var/vmail" "var-vmail" fi if [[ -d "var/www" ]] ; then - dir_backup "var/www" "var-www" "y" + dir_backup "var/www" "var-www" fi for odir in opt/* ; do @@ -352,42 +315,119 @@ do_dir_backup() { } #------------------------------------------------------------------------------ -do_mysql_backup(){ +eval_mysql_databases() { - local dumpfile="${BACKUP_DIR}/mysql.dump.all-dbs.dump.sql.gz" - local errorlog="${BACKUP_DIR}/mysql.dump.error.log" + local dbname= + local oifs="${IFS}" + IFS=" +" + local db= + local db_uc= + local do_ignore= empty_line - info "Dumping MySQL Datenbank -> '${CYAN}${dumpfile}${NORMAL}' ..." + info "Evaluating all databases for backup." + + for dbname in $( mysql -s -r -N -e 'SHOW DATABASES' ) ; do + + if [[ "${dbname}" == 'performance_schema' ]] ; then + continue + elif [[ "${dbname}" == 'information_schema' ]] ; then + continue + fi + + db_uc=$( echo "${dbname}" | tr '[:upper:]' '[:lower:]' ) + do_ignore="n" + for db in "${!ALL_DATABASES_IGNORE[@]}" ; do + if [[ "${db}" == "${db_uc}" ]] ; then + do_ignore="y" + break + fi + done + if [[ "${do_ignore}" == "y" ]] ; then + debug "Ignoring database '${CYAN}${dbname}${NORMAL}'." + continue + fi + + debug "Adding database '${CYAN}${dbname}${NORMAL}'." + DATABASES+=( "${dbname}" ) + + done + if [[ "${DEBUG}" == 'y' ]] ; then + declare -p DATABASES + fi - local cmd="mysqldump --all_databases --routines --triggers --add-drop-database" - cmd+=" --add-drop-table --complete-insert --extended-insert --lock-tables" - if [[ "${VERBOSE}" ]] ; then + IFS="${oifs}" + + if [[ "${VERBOSE}" == "y" ]] ; then + echo + echo "Following databases will be backed up:" + for dbname in "${DATABASES[@]}" ; do + echo " * '${dbname}'" + done + fi + + +} + +#------------------------------------------------------------------------------ +backup_mysql_database() { + + local db="${1}" + local dumpfile="${BACKUP_DIR}/mysql.dump.${db}.sql.gz" + + empty_line + info "Backup of database '${CYAN}${db}${NORMAL}' into file '${dumpfile}' ..." + + local db_uc=$( echo "${db}" | tr '[:upper:]' '[:lower:]' ) + + local cmd="mysqldump --routines --triggers --add-drop-database --add-drop-table" + cmd+=" --complete-insert --extended-insert --lock-tables" + cmd+=" --opt --flush-logs --single-transaction" + cmd+=" --databases \"${db}\" " + if [[ "${VERBOSE}" == "y" ]] ; then cmd+=" --verbose" fi - cmd+=" --log-error=\"${errorlog}\"" + cmd+=" --log-error=\"${MYSQL_ERRORLOG}\"" cmd+=" | gzip -9" - if [[ "${VERBOSE}" ]] ; then + if [[ "${VERBOSE}" == "y" ]] ; then cmd+=" --verbose" fi cmd+=" > \"${dumpfile}\"" - if [[ "${SIMULATE}" ]] ; then + + if [[ "${SIMULATE}" == "y" ]] ; then info "Executing: ${cmd}" - return + else + debug "Executing: ${cmd}" + eval ${cmd} fi - debug "Executing: ${cmd}" - eval ${cmd} - if [[ -e "${errorlog}" ]] ; then - if [[ -s "${errorlog}" ]] ; then - cmd="gzip -9 \"${errorlog}\"" - if [[ "${VERBOSE}" ]] ; then - cmd="gzip -9 --verbose \"${errorlog}\"" + +} + +#------------------------------------------------------------------------------ +do_mysql_backup(){ + + local dbname= + + MYSQL_ERRORLOG="${BACKUP_DIR}/mysql.dump.error.log" + + eval_mysql_databases + + for dbname in "${DATABASES[@]}" ; do + backup_mysql_database "${dbname}" + done + + if [[ -e "${MYSQL_ERRORLOG}" ]] ; then + if [[ -s "${MYSQL_ERRORLOG}" ]] ; then + cmd="gzip -9 \"${MYSQL_ERRORLOG}\"" + if [[ "${VERBOSE}" == "y" ]] ; then + cmd="gzip -9 --verbose \"${MYSQL_ERRORLOG}\"" fi info "Executing: ${cmd}" eval ${cmd} else - debug "Removing empty '${CYAN}${errorlog}${NORMAL}' ..." - RM "${errorlog}" + debug "Removing empty '${CYAN}${MYSQL_ERRORLOG}${NORMAL}' ..." + RM "${MYSQL_ERRORLOG}" fi fi @@ -402,16 +442,16 @@ do_postgres_backup() { debug "Dumping PostgreSQL globals ..." local dumpfile="${BACKUP_DIR}/postgres.@globals.dump.sql.gz" local cmd="su - postgres -c \"pg_dumpall" - if [[ "${VERBOSE}" ]] ; then + if [[ "${VERBOSE}" == "y" ]] ; then cmd+=" --verbose" fi cmd+=" --globals-only --clean --encoding=utf-8 --disable-triggers --if-exists\"" cmd+=" | gzip -9" - if [[ "${VERBOSE}" ]] ; then + if [[ "${VERBOSE}" == "y" ]] ; then cmd+=" --verbose" fi cmd+=" > \"${dumpfile}\"" - if [[ "${SIMULATE}" ]] ; then + if [[ "${SIMULATE}" == "y" ]] ; then info "Executing: ${cmd}" else debug "Executing: ${cmd}" @@ -429,16 +469,16 @@ do_postgres_backup() { debug "Dumping PostgreSQL database '${CYAN}${db}${NORMAL}' ..." dumpfile="${BACKUP_DIR}/postgres.${db}.dump.sql.gz" cmd="su - postgres -c \"pg_dump" - if [[ "${VERBOSE}" ]] ; then + if [[ "${VERBOSE}" == "y" ]] ; then cmd+=" --verbose" fi cmd+=" --blobs --clean --create --encoding=utf-8 --disable-triggers --if-exists '${db}'\"" cmd+=" | gzip -9" - if [[ "${VERBOSE}" ]] ; then + if [[ "${VERBOSE}" == "y" ]] ; then cmd+=" --verbose" fi cmd+=" > \"${dumpfile}\"" - if [[ "${SIMULATE}" ]] ; then + if [[ "${SIMULATE}" == "y" ]] ; then info "Executing: ${cmd}" continue fi @@ -448,71 +488,6 @@ do_postgres_backup() { } -#------------------------------------------------------------------------------ -do_backup_ldap() { - - - if ps -ef | grep slapd | grep -v grep >/dev/null ; then - : - else - debug "OpenLDAP Server is not running." - return - fi - - local dumpfile="${BACKUP_DIR}/ldap-cfg.dump.ldif.gz" - - empty_line - info "Dumping OpenLDAP Config -> '${CYAN}${dumpfile}${NORMAL}' ..." - local cmd="ldapsearch -Y EXTERNAL -Q -LLL -o ldif-wrap=no -H ldapi:/// -b \"cn=config\"" - if [[ "${VERBOSE}" ]] ; then - cmd+=" -v" - fi - cmd+=" | gzip -9" - if [[ "${VERBOSE}" ]] ; then - cmd+=" --verbose" - fi - cmd+=" > \"${dumpfile}\"" - if [[ "${SIMULATE}" ]] ; then - info "Executing: ${cmd}" - else - debug "Executing: ${cmd}" - eval ${cmd} - fi - - local dn= - local clean_dn= - - for dn in "${LDAP_ROOT_DNS[@]}" ; do - - clean_dn=$( echo "${dn}" | sed -e 's/^[ ]*//' -e 's/[ ]*$//' -e 's/[ ][ ]*/_/g' ) - dumpfile="${BACKUP_DIR}/ldap-db.${clean_dn}.dump.ldif.gz" - - empty_line - info "Dumping OpenLDAP Datenbank '${CYAN}${dn}${NORMAL}' -> '${CYAN}${dumpfile}${NORMAL}' ..." - - cmd="ldapsearch -Y EXTERNAL -Q -LLL -o ldif-wrap=no -H ldapi:///" - if [[ "${VERBOSE}" ]] ; then - cmd+=" -v" - fi - cmd+=" -b \"${dn}\" '+' '*' | gzip -9" - if [[ "${VERBOSE}" ]] ; then - cmd+=" --verbose" - fi - cmd+=" > \"${dumpfile}\"" - if [[ "${SIMULATE}" ]] ; then - info "Executing: ${cmd}" - else - debug "Executing: ${cmd}" - eval ${cmd} - fi - - done - - debug "Finished LDAP dump." - -} - - #------------------------------------------------------------------------------ create_checksums() { @@ -531,7 +506,7 @@ create_checksums() { cs_file="backup-checksums.${cs_type}" info "Creating '${CYAN}${cs_file}${NORMAL}' ..." cmd="${cs_type}sum *.gz > \"${cs_file}\"" - if [[ "${SIMULATE}" ]] ; then + if [[ "${SIMULATE}" == "y" ]] ; then info "Executing: ${cmd}" continue fi @@ -583,6 +558,7 @@ clean_old_backups() { info "Removing '${bdir}' ..." RM --recursive "${bdir}" + done } @@ -598,16 +574,16 @@ sync_to_remote() { empty_line info "Syncing backup to '${GREEN}${rhost}${NORMAL}:${CYAN}${BACKUP_HOSTDIR}${NORMAL}' ..." cmd="rsync --archive --hard-links --delete --stats" - if [[ "${VERBOSE}" ]] ; then + if [[ "${VERBOSE}" == "y" ]] ; then cmd+=" --verbose" fi cmd+=" \"${BACKUP_HOSTDIR}\" \"${rhost}:${BACKUP_PARENTDIR}\"" - if [[ "${QUIET}" ]] ; then + if [[ "${QUIET}" == "y" ]] ; then cmd+=" >> \"${LOGFILE}\" 2>&1" else cmd+=" 2>&1 | tee -a \"${LOGFILE}\"" fi - if [[ "${SIMULATE}" ]] ; then + if [[ "${SIMULATE}" == "y" ]] ; then info "Executing: ${cmd}" continue fi @@ -621,7 +597,6 @@ sync_to_remote() { #------------------------------------------------------------------------------ main() { - eval_config get_options "$@" umask 0022 @@ -631,19 +606,28 @@ main() { empty_line check_preferences - do_dir_backup + MKDIR -p "${BACKUP_DIR}" + + if [[ "${DO_DIR_BACKUP}" == 'y' ]] ; then + do_dir_backup + else + empty_line + warn "Don't execute directory backups." + fi if [[ "${DO_MYSQL}" == "y" ]] ; then do_mysql_backup fi if [[ "${DO_POSTGRES}" == "y" ]] ; then do_postgres_backup fi - if [[ "${DO_LDAP}" == "y" ]] ; then - do_backup_ldap - fi create_checksums clean_old_backups - sync_to_remote + if [[ "${DO_SYNC}" == "y" ]] ; then + sync_to_remote + else + empty_line + warn "Don't execute the sync to the remote hosts." + fi info "Finished." } -- 2.39.5