mirror of https://github.com/pditzel/dbb.git

Patrick Ditzel
14.16.2017 73b16f84d25c73401a056e26ebbd3504ecb3c272
As this program grwos and grows it was time do make an own repository for it an move it into.
12 files added
550 ■■■■■ changed files
INSTALL.md 13 ●●●●● patch | view | raw | blame | history
README.md 23 ●●●●● patch | view | raw | blame | history
TODO.md 26 ●●●●● patch | view | raw | blame | history
config/dbb.cfg 40 ●●●●● patch | view | raw | blame | history
config/mariadb.cfg 11 ●●●●● patch | view | raw | blame | history
config/mongodb.cfg 11 ●●●●● patch | view | raw | blame | history
config/postgresql.cfg 19 ●●●●● patch | view | raw | blame | history
dbb 234 ●●●●● patch | view | raw | blame | history
dbb-modules/mariadb 19 ●●●●● patch | view | raw | blame | history
dbb-modules/mongodb 5 ●●●●● patch | view | raw | blame | history
dbb-modules/postgresql 138 ●●●●● patch | view | raw | blame | history
install.sh 11 ●●●●● patch | view | raw | blame | history
INSTALL.md
New file
@@ -0,0 +1,13 @@
# Installation of the script
1.) Run the install.sh - script
```bash
./install.sh
```
2.) Edit the configfile that it fits to your environment.
3.) Make changes to the skript and some pull requests ;-).
README.md
New file
@@ -0,0 +1,23 @@
# Databasebackup (dbbackup)
This is a bash-script to backup your databases with the most common standard tools.
## Requirenments
Important: This Script is developed with debian GNU/Linux so it should work on debian and the most derived distributions.
For the backup of your databases you need a propper client to connect to your databaseserver.
This script aims to backup many different databasetype eg. postgres, mysql or mongodb in one single program. So if you have to backup postgres you have to install the psql-client package. If you want to backup MySQL databases install the mysql-client package.
## Features
* Runs interactive and noninteractive
* Make Postgrsbackups (localy and remote)
* Make MySQL/MariaDB-Backups (coming soon)
* Make MongoDB-Backups (coming soon)
* Optinal keep a filehistory of backups
* Optinal logging to syslog
* Reads configuration for postgresbackups from ~/.pgpass
More Information here: [https://www.central-computer.de/datenbanken-backup/]
TODO.md
New file
@@ -0,0 +1,26 @@
# ToDo-List
Ideas for the future
## Database Options
### MariaDB / MySQL
- [ ] Backup MariaDB / MySQL on the local machine
- [ ] Backup MariaDB / MySQL on remote machines
### MongoDB
- [ ] Backup MongoDB on the local host
- [ ] Backup MongoDB on remote machines
### Oracle
- [ ] Check if it possible to dump OracleDatabases
- [ ] Backup the local host
- [ ] Backup remote hosts
## General Functionality
- [ ] Run single backuptasks in background (using "&"" and "wait")
- [ ] Run script in interactive mode and tell it what db on what host with which user an pwd (<- only interactive) (using a script alias and do interactiv or noninteractive depending on the calling name)
- [x] Adding an optional filehistory of the backuped files/dumps (specify an timerange or a number how many dumps should be saved)
config/dbb.cfg
New file
@@ -0,0 +1,40 @@
################################################################################
# Configure the einvironment:
################################################################################
#
################################################################################
# Should dbbackup log to syslog (TRUE | FALSE)
# Default is TURE
ENABLE_SYSLOG=TRUE
################################################################################
# Enable debugout
# Default is FALSE
ENABLE_DEBUG=TRUE
################################################################################
# Where to backup datafiles?
BACKUP_DIR=/home/backupuser/database_backups
################################################################################
# We need a tmpdir
TMP_DIR=/tmp/databases
################################################################################
# Which user is running dbbackup?
BACKUPUSER=backupuser
################################################################################
# Should a history of backuped files kept?
KEEP_BACKUP_FILES=TRUE
# How many days should these files kept?
BACKUP_FILES_DAYS=14
config/mariadb.cfg
New file
@@ -0,0 +1,11 @@
################################################################################
# ToDo
MYSQL_BACKUP_LOCAL=FALSE
################################################################################
# ToDo
MYSQL_BACKUP_REMOTE=FALSE
################################################################################
config/mongodb.cfg
New file
@@ -0,0 +1,11 @@
################################################################################
# ToDo
MONGODB_BACKUP_LOCAL=FALSE
################################################################################
# ToDo
MONGODB_BACKUP_REMOTE=FALSE
################################################################################
config/postgresql.cfg
New file
@@ -0,0 +1,19 @@
################################################################################
# Backup Postgres @ localhost as user postres (Debian)
POSTGRES_BACKUP_LOCAL=TRUE
# Should every database backuped in a single file?
# Works together with POSTGRES_BACKUP_LOCAL_DUMP_ALL
POSTGRES_BACKUP_LOCAL_SINGLE=TRUE
# Should all databases backuped in one large file?
# Works together with POSTGRES_BACKUP_LOCAL_SINGLE
POSTGRES_BACKUP_LOCAL_DUMP_ALL=TRUE
################################################################################
## Enable backup of remote postgres databases specified in ~/.pgpass
POSTGRES_BACKUP_REMOTE=TRUE
dbb
New file
@@ -0,0 +1,234 @@
#!/bin/bash
################################################################################
#                                                                              #
# Author: Patrick Ditzel (patrick@central-computer.de)                         #
# Lizenz:  GNU GENERAL PUBLIC LICENSE v3                                       #
#                                                                              #
################################################################################
################################################################################
# Set up the backupenvironment and "global" functions
################################################################################
INSTALLATION_PATH_PREFIX=/usr/local
function set_config {
    if [ -r /etc/dbb.cfg ]; then
        # Check if configuration is found in /etc. If yes set configvar
        BACKUPCFG=/etc/dbb.cfg
    elif [ -r ~/.dbb.cfg ]; then
        # If config is found in the backupuser home directory set it into the configvar
        BACKUPCFG=~/.dbb.cfg
    else
        echo "No configuration file is found, please create one" | /usr/bin/logger -s -i -t databasebackup
    fi
}
function load_dbmodul_dfg {
    if [ -d $BACKUPCFG.d ]; then
        if [ ! "$(ls -A $BACKUPCFG.d)" ]; then
            echo "Configurationdirectory for modules exist but it is empty" | /usr/bin/logger -s -i -t databasebackup
        else
            for MODULCFG in $(ls $BACKUPCFG.d); do . $BACKUPCFG.d/MODULCFG; done
        fi
    else
        echo "Configurationdirectory does nort exists, can't load any configurationfile" | /usr/bin/logger -s -i -t databasebackup
    fi
}
function check_backup_env {
    # Check if the configuration exists and is not empty
    if [ -r $BACKUPCFG ] && [ -s $BACKUPCFG ]; then
        # If true then read it
        . $BACKUPCFG
        load_dbmodul_dfg
    else
        # If not throw an errormessage
        echo "The configfile does not exists or is empty" | /usr/bin/logger -s -i -t databasebackup
        echo "Please create the $BACKUPCFG or write your settings into" | /usr/bin/logger -s -i -t databasebackup
        exit 1
    fi
    if [ "$ENABLE_DEBUG" = "TRUE" ]; then
        # If debugoutput is enabled show the configurationfile without comments
        echo "################################################################################" | /usr/bin/logger -s -i -t databasebackup
        while read -r configline; do
            echo "$configline" | grep -v '^$' | grep -v '^#' | /usr/bin/logger -s -i -t databasebackup
        done <<< "$(cat $BACKUPCFG)"
        echo "################################################################################" | /usr/bin/logger -s -i -t databasebackup
    fi
    # Check if the target directory for the backupfiles exists
    if [ ! -d "$BACKUP_DIR" ]; then
        # If not create it
        mkdir -p "$BACKUP_DIR"
    fi
    # Check if the directory for tempfiles exists
    if [ ! -d "$TMP_DIR" ]; then
        # If not create it
        mkdir -p "$TMP_DIR"
    fi
}
function set_logger {
    # Check if log to syslog is enabled
    if [ "$ENABLE_SYSLOG" = "TRUE" ]; then
        # If true then define the logger
        LOGGER="/usr/bin/logger -s -i -t databasebackup"
    else
        # If not cat it out on stdout
        LOGGER="/bin/cat"
    fi
}
function debug {
        DEBUGMSG=$1
        if [ "$ENABLE_DEBUG" = "TRUE" ]; then
                echo "$DEBUGMSG" | $LOGGER
        fi
}
function load_dbmodules {
    if [ -d $BACKUPCFG.d ] && [ -d $INSTALLATION_PATH_PREFIX/lib/dbb-modules ]; then
        if [ ! "$(ls -A $BACKUPCFG.d)" ] && [ ! "$(ls -A $INSTALLATION_PATH_PREFIX/lib/dbb-modules)" ]; then
            debug "Configurationdirectory or directory for modules exist but it is empty"
        else
            for MODUL in $(ls $BACKUPCFG.d | cut -d "." -f1); do
                . $INSTALLATION_PATH_PREFIX/lib/dbb-modules/$MODUL
                debug "Load module: $INSTALLATION_PATH_PREFIX/lib/dbb-modules/$MODUL"
                check_$MODUL_deps
            done
        fi
    else
        debug "Configurationdirectory does nort exists, can't load any configurationfile"
    fi
}
function is_interactive {
    SCRPT=$(basename "$0")
    debug "$SCRPT"
    if [ "$SCRPT" = "dbbi" ]; then
        # If the script is called for interactive use we have to chenge the calls of the functions
        # Setting the $LOGGER für interactive use to /bin/cat
        LOGGER="/bin/cat"
        # Here we set teh environment variable for interactive use
        debug "dbbi (DataBase Interactive Backup) is called"
        RADIOACTIVE=TRUE
    elif [ "$SCRPT" = "dbb" ]; then
        # Set the $LOGGER
        LOGGER="/usr/bin/logger -s -i -t databasebackup"
        # If the script is used noninteractive we have also to set the environmet variable with this information
        debug "dbb (DataBase Backup) is called"
        RADIOACTIVE=FALSE
        # unset the $LOGGER because this will be set later within the informatione in the configfile
        unset LOGGER
    else
        # If the switch between interactive and noninteractive does not work: tell it but before set the $LOGGER
        LOGGER="/usr/bin/logger -s -i -t databasebackup"
        debug "An error occured - don't know if to use interactive or noninteractive"
        exit 1
    fi
}
function backup_file_handler {
    # translate the vars to make it more readable
    BFH_TMP_DIR=$1
    BFH_BACKUPDIR_DIR=$2
    BFH_FILE=$3
    # If enabled put out some debug infos
    debug "BFH_TMP_DIR: $BFH_TMP_DIR"
    debug "BFH_BACKUPDIR_DIR: $BFH_BACKUPDIR_DIR"
    debug "FILE: $BFH_FILE"
    # Check if the script should keep a filehistorie
    if [ "$KEEP_BACKUP_FILES" = "TRUE" ]; then
        debug "Keep history"
        # Set some vars to manage the files
        BACKUP_DAY=$(date +%x)
        REMOVE_NUMBER=$(( $BACKUP_FILES_DAYS + 1 ))
        BFH_FILE_PREFIX_NAME_TO_REMOVE=$(date -d "$REMOVE_NUMBER days ago" "+%x")
        # ... and if it is turned on give some debig info
        debug "BACKUP_DAY: $BACKUP_DAY"
        debug "REMOVE_NUMBER: $REMOVE_NUMBER"
        debug "FILE_PREFIX_NAME_TO_REMOVE: $BFH_FILE_PREFIX_NAME_TO_REMOVE-$BFH_FILE"
        # Check if there is an backupfile from the current day
        if [ -f "$BFH_BACKUPDIR_DIR"/"$BACKUP_DAY"-"$BFH_FILE" ]; then
            # If yes append miniutes and seconds to the date-profix of the filename
            debug "File $BFH_BACKUPDIR_DIR/$BACKUP_DAY-$BFH_FILE already exists. Rename the new one."
            DATE_TIME_SUFFIX=$(date +%H%M%S)
            # ... and move it into the targetdir
            mv "$BFH_TMP_DIR"/"$BFH_FILE" "$BFH_BACKUPDIR_DIR"/"$BACKUP_DAY"-"$DATE_TIME_SUFFIX"-"$BFH_FILE"
        else
            # If there is no backupfile of the current day move it to the backupfolder
            mv "$BFH_TMP_DIR"/"$BFH_FILE" "$BFH_BACKUPDIR_DIR"/"$BACKUP_DAY"-"$BFH_FILE"
        fi
        # Check if there are files older then the days to keep set in the config
        if [ -f "$BFH_BACKUPDIR_DIR"/"$BFH_FILE_PREFIX_NAME_TO_REMOVE"-"$BFH_FILE" ]; then
            # if yes remove it
            rm "$BFH_BACKUPDIR_DIR"/"$BFH_FILE_PREFIX_NAME_TO_REMOVE"-"$BFH_FILE"
            # Also remove the files with the extended prefix in the name
            # If there is ab file with the extende prefix then there has to be a file with tne normal prefix
            rm "$BFH_BACKUPDIR_DIR"/"$BFH_FILE_PREFIX_NAME_TO_REMOVE"?????-"$BFH_FILE"
        else
            # If no file exists do nothing but some debuginfo
            debug "File $BFH_BACKUPDIR_DIR/$BFH_FILE_PREFIX_NAME_TO_REMOVE-$BFH_FILE does not exists, so can not remove it."
        fi
    else
        # If we do not keep a filehistory do the following
        # Check if the targefile exists
        if [ -f "$BFH_BACKUPDIR_DIR"/"$BFH_FILE" ]; then
            debug "$BFH_FILE exists ... make a diff"
            # Check if there are differences betwenn last backup and the actual one
            diff "$BFH_TMP_DIR"/"$BFH_FILE" "$BFH_BACKUPDIR_DIR"/"$BFH_FILE" > /dev/null 2>&1
            if [ $? -ne 0 ]; then
                # If yes then move it to the backupfolder
                debug "Differences found between old and new $BFH_FILE -> moving to BACKUP_DIR"
                mv "$BFH_TMP_DIR"/"$BFH_FILE" "$BFH_BACKUPDIR_DIR"/"$BFH_FILE"
            else
                # If not do nothing
                debug "No differences found between old an new $BFH_FILE"
            fi
        else
            # If there is a new databasedumpfile move it to the backupfolder
            debug "New Backupfile $BFH_FILE -> moving to $BFH_BACKUPDIR_DIR"
            mv "$BFH_TMP_DIR"/"$BFH_FILE" "$BFH_BACKUPDIR_DIR"/"$BFH_FILE"
        fi
    fi
}
function check_global_deps {
    # Check the dependencys
    if [ ! -e /usr/bin/sudo ]; then
        echo "It seems that you dont have sudo installed. Please install sudo and restart" | /usr/bin/logger -s -i -t databasebackup
        exit 1
    fi
}
################################################################################
# The mainfunktion
function main {
    check_global_deps
    is_interactive
    if [ "$RADIOACTIVE" = "TRUE" ]; then
        debug "Unsing dbbi (dbb interactive = dbbi) is for future use"
    fi
    if [ "$RADIOACTIVE" = "FALSE" ]; then
        debug "running noninteractive"
        # Set up the configuration for the noninteractive mode
        set_config
        # Configure logging (from configurationfil)e
        set_logger
        # Check if the backupenvironment is setup properly
        check_backup_env
        # Run modul-main-functions
        for MODULMAIN in $(ls $BACKUPCFG.d | cut -d "." -f1); do
            $MODULMAIN_main
        done
            # The final action: remove the dumps
        rm -rf "$TMP_DIR"
    fi
}
main
dbb-modules/mariadb
New file
@@ -0,0 +1,19 @@
#!/bin/bash
# MariaBD/MySQL remote
#
# The Information what MySQL/MariaDB - databases should be backuped are defined in ~/.my.cnf
function run_mysql_backups {
    debug "Dump remote database $MYSQLDB from $MYSQLDBHOST"
    /usr/bin/mysqldump --skip-dump-date -h "$MYSQLDBHOST" -u "$MYSQLDBUSER" -p"$MYSQLPASSWD" "$MYSQLDB" > "$TMP_DIR"/"$MYSQLDBHOST"_"$MYSQLDB".mysql
    debug "Diff MySQLDump $MYSQLDB"
    diff "$TMP_DIR"/"$MYSQLDBHOST"_"$MYSQLDB".mysql "$BACKUP_DIR"/"$MYSQLDBHOST"_"$MYSQLDB".mysql > /dev/null 2>&1
    if [ $? -ne 0 ]; then
        debug "Differences found -> moving to BACKUP_DIR"
            mv "$TMP_DIR"/"$MYSQLDBHOST"_"$MYSQLDB".mysql "$BACKUP_DIR"/"$MYSQLDBHOST"_"$MYSQLDB".mysql
    else
            debug "No differences found an Database $MYSQLDB"
    fi
    echo ""
}
dbb-modules/mongodb
New file
@@ -0,0 +1,5 @@
#!/bin/bash
function run_mongodb_backup {
    echo ""
}
dbb-modules/postgresql
New file
@@ -0,0 +1,138 @@
#!/bin/bash
# dependencies
function check_postgresql_deps {
    if [ ! -e /usr/bin/psql ]; then
        debug "It seems that you dont have psql installed. You may have problems to backup remote databases"
    fi
    numberRegex='^[0-9]+$'
    if ! [[ $(id -u postgres 2>&1) =~ $numberRegex ]] ; then
        debug "It seems that you dont have the user postgres on your computer. You may have problems to backup local postgres databases"
    fi
}
# PostgreSQL local
function pg_local_all {
    # Debugoutput id DEBUG is enabled
    debug "Dump all from Postgres local"
    # Dump all databases in one file as user postgres (Debian)
    sudo -H -i -u postgres pg_dumpall > "$TMP_DIR"/local_dumpall.pgsql
    debug "Diff alldumps from Postgres local"
    # Check if there are differences between the actual dump and the last dump
    backup_file_handler "$TMP_DIR $BACKUP_DIR" local_dumpall.pgsql
}
function pg_local_single {
    # Get a list with all databases on localhost. Do it as user postgres (Debian)
    # parallelize the following
    for DB in $(sudo -H -i -u postgres /usr/bin/psql -At -c "SELECT datname FROM pg_database WHERE NOT datistemplate AND datallowconn ORDER BY datname;" postgres)
        do
            debug "Dumping local database $DB"
            # Dump each database in a single file
            sudo -H -i -u postgres /usr/bin/pg_dump -Fp "$DB" > "$TMP_DIR"/local_"$DB".pgsql
            backup_file_handler "$TMP_DIR" "$BACKUP_DIR" local_"$DB".pgsql
            echo ""
        done
}
# Do the local backupjobs
function run_local_pg_backups {
    # Test if the current backupuser has access via sudo to postgres
    # This part has to be improved!
    sudo -l -U "$BACKUPUSER" | grep postgres
    if [ $? -eq 0 ];then
        # If the user has access vi sudo to postgres and a full dump is configured, do it.
        if [ "$POSTGRES_BACKUP_LOCAL_DUMP_ALL" == "TRUE" ]; then
            pg_local_all
        fi
        # If the user has access vi sudo to postgres and dumps for each database is configured , do it.
        if [ "$POSTGRES_BACKUP_LOCAL_SINGLE" == "TRUE" ]; then
            pg_local_single
        fi
    else
        # If the user is not permitted to acces the postgresdatabases vi sudo throw an errormessage
        echo "" | $LOGGER
        echo "The backupuser does not the permission to act as user postgres" | $LOGGER
        echo "Please add the following line to your /etc/sudoers:" | $LOGGER
        echo "backupuser ALL=(postgres) NOPASSWD: /usr/bin/psql,/usr/bin/pg_dump" | $LOGGER
        echo "" | $LOGGER
    fi
}
################################################################################
# Postgres remote
#
# All databases on remotehosts defined in the ~/.pgpass file will be backuped.
# So the ~/.pgpass is the configurationfile for this part!
function dump_remote_pgdb {
    # Translate params ;-)
    TRGTHOST=$1
    TRGTPORT=$2
    TRGTDB=$3
    TRGTBDUSER=$4
    # If debug is enabled, check the translated params
    debug "PostgreSQL:"
    debug "    Host: $TRGTHOST"
    debug "    Port: $TRGTPORT"
    debug "    Database: $TRGTDB"
    debug "    User: $TRGTBDUSER"
    debug "Testing TLS-Connection"
    # Check if the connection to the postgres-server are encryptet (here we force with sslmode=require)
    psql -U "$TRGTBDUSER" postgresql://"$TRGTHOST":"$TRGTPORT"/"$TRGTDB"?sslmode=require -c '\conninfo' | grep TLS > /dev/null 2>&1
    if [ "$?" -eq "0" ]; then
        debug "Dumping remote database $TRGTHOST-$TRGTDB"
        # If we successfuly testet the encrypted connection to the postgres-server we try to force the sslmode
        # I don't know if the following statement really effect to pg_dump :-(
        export PGSSLMODE=require
        # Dump the databases which are defined in the params
        /usr/bin/pg_dump -U "$TRGTBDUSER" -h "$TRGTHOST" -p "$TRGTPORT" "$TRGTDB" > "$TMP_DIR"/"$TRGTHOST"-"$TRGTDB".pgql
        backup_file_handler "$TMP_DIR" "$BACKUP_DIR" "$TRGTHOST"-"$TRGTDB".pgql
    else
        # If no encrypted connection to the postgres-server can be established throw an errormessage
        echo "" | $LOGGER
        echo "Could not establish a TLS encrypted connection the the databasehost." | $LOGGER
        echo "Please configure the connections with hostssl in pg_hba.conf." | $LOGGER
        echo "" | $LOGGER
    fi
    echo ""
}
function run_remote_pg_backups {
    # Check if the remoebackup for postgres is configured
    if [ "$POSTGRES_BACKUP_REMOTE" = "TRUE" ]; then
        # If yes the check for the ~/.pgpass-file. Here are the remotedatabases specified
        if [ -r ~/.pgpass ]; then
            # parallelize the following
            while read -r LINE; do
                # For each entry do the backup
                debug "run dump with params $LINE"
                # CAUTION: No doublequotes in the following line. The var $LINE has to be splittet!
                                dump_remote_pgdb $LINE
            # To get the params for the function the .pgpass-file is striped from the comments,
            # the ":" are replaces against whitespaces and only the first four coloums are used
            # so we give "host port database user" to the function
            done <<< "$(cat ~/.pgpass | grep -v '#' | tr ":" " " | cut -d " " -f1,2,3,4)"
        else
            # If the ~/.pgpass-file is missig, throw an errormessage
            echo "" | $LOGGER
            echo "The ~/.pgpass file is missing, no remote postgres databases will be backuped." | $LOGGER
            echo "If you want do backup postgres reomte databases, please create a ~/.pgpass file in the homedirectory of your backupuser (https://wiki.postgresql.org/wiki/Pgpass)." | $LOGGER
            echo "" | $LOGGER
        fi
    fi
    echo ""
}
function postgres_main {
    if [ "$POSTGRES_BACKUP_LOCAL" = "TRUE" ]; then
        run_local_pg_backups
    fi
    if [ "$POSTGRES_BACKUP_REMOTE" = "TRUE" ]; then
        run_remote_pg_backups
    fi
}
install.sh
New file
@@ -0,0 +1,11 @@
#/bin/bash
# ToDo
#
# 1. Set installationpath (e.g. /usr/ or /usr/local/) => INSTPATH
# 2. Generate directories
#   - $INSTPATH/lib/dbb
# 3. Check if it is an local user installation odr a global system installation
# 4. If it is a global installation mkdit /etc/dbb.cfg.d an cop dbb.cf to /etc
#    If it is an local user installation create ~/.dbb.cfg.d an cop dbb.cfg to ~/.ddb.cfg
# 5. Copy dbb to $INSTALLPATH/bin/dbb and create symlink from $INSTALLPATH/bin/dbb to $INSTALLPATH/bin/dbbi