#!/bin/bash # # @file # @brief Cella wraps backup tools, defines and runs backup jobs # # @author code@edoceo.com # @copyright 2008-2011 Edoceo, Inc http://edoceo.com/ # @license MIT # @see http://edoceo.com/creo/cella # # Cella does backups of files and databases using standard tools # rdiff and rsync for file backups # mysqldump and pg_dump for database backups # ldapsearch or slapcat for OpenLDAP # svn-hot-backup for Subversion # git ? # ./cella.sh script.sh # ./cella.sh --log=/var/log/cella.log script.sh # ./cella.sh --log=/var/log/cella.err --log=/var/log/cella.log script.sh # ./cella.sh --debug script.sh # ./cella.sh --verbose script.sh # ./cella.sh # I need this to run _cella_dir=$(dirname $(readlink -f "${BASH_SOURCE[0]}") ) # sourced or executed? _cella_exp=$( [[ "${BASH_SOURCE[0]}" != "$0" ]] && echo "true" ) _cella_err="/dev/stderr" _cella_log="/dev/null" # utility variables _cella_mysql_host= _cella_mysql_user= _cella_mysql_pass= _cella_pgsql_host= _cella_pgsql_user= _cella_pgsql_fmt="custom" _cella_rdiff_age="21D" _cella_runas= set -o allexport set -o errtrace set -o noclobber if [ "$_cella_exp" != "true" ]; then set -o errexit fi # Show Help function cella_help() { echo "Cella Shell Based Backup Script" if [ "$_cella_exp" != "true" ]; then echo "${BASH_SOURCE[0]} --debug --verbose --err=[file] --log=[file] [script]" fi echo -n "Support:" which rsync >/dev/null 2>&1 && echo -n " rsync" which rdiff-backup >/dev/null 2>&1 && echo -n " rdiff (--age=$_cella_rdiff_age)" which mysqldump >/dev/null 2>&1 && echo -n " mysql" which pg_dump >/dev/null 2>&1 && echo -n " postgres" which ldapsearch >/dev/null 2>&1 && echo -n " ldap" which svn-hot-backup >/dev/null 2>&1 && echo -n " svn" echo echo echo "Update: curl http://cdn.edoceo.com/bin/cella.sh > ${BASH_SOURCE[0]}" echo if [ "$_cella_exp" == "true" ]; then echo echo "Cella routines have been exported to the current shell environment" echo fi } export -f cella_help # Run the next commands as this user via sudo # @param $1 = Username function cella_runas() { username=$1 # Using su won't work cause username comes after command :( # _cella_runas="su --command """ _cella_runas="sudo -H -n -u $username -- " } export -f cella_runas # # Backup via rdiff-backup # @param $1 = rdiff source path # @param $2 = rdiff target path # @param $3 = rdiff age function rdiff_backup() { source=$1 target=$2 # Use default, else supplied maxage=$_cella_rdiff_age if [[ $# == 3 ]]; then maxage=$3; fi # Execute $_cella_runas rdiff-backup \ --backup-mode \ --create-full-path \ --exclude-other-filesystems \ --verbosity=4 \ "$source" \ "$target" \ 1>>$_cella_log 2>>$_cella_err # 2>&1 | ( grep -v 'does not match remote' || true ) # If maxage specified then trim if [[ -n "$maxage" ]]; then $_cella_runas rdiff-backup \ --force \ --remove-older-than "$maxage" \ "$target" \ 1>>$_cella_log 2>>$_cella_err fi # # rdiff-backup --list-increment-sizes _cella_runas= return 0 } export -f rdiff_backup # # Backup via rsync # @param $1 = rsync source path # @param $2 = rsync target path # @param $3 = options to rsync function rsync_backup() { source=$1 target=$2 option=$3 $_cella_runas rsync \ --archive \ --delete-before \ --one-file-system \ $option \ "$source" \ "$target" \ 1>>$_cella_log 2>>$_cella_err _cella_runas= return 0 } export -f rsync_backup # # Backup MySQL # @param $1 = source, "." for all on localhost, "$server/$database" or "$server/." # @param $2 = target directory # @param $3 = Username # @param $4 = Password function mysql_backup() { # Hostname/Database hostname=$(echo "$1"|cut -d'/' -f1) database=$(echo "$1"|cut -d'/' -f2) if [[ "$hostname" == "$database" ]]; then hostname="" fi # Hostname/Database if [[ -n "$hostname" ]]; then _cella_mysql_host="--host=$hostname" fi # Path dumppath=$2 if [[ ! -d "$dumppath" ]]; then mkdir -p "$dumppath" fi # User if [[ -n "$3" ]]; then _cella_mysql_user="--user=$3" fi _cella_mysql_pass="--password=$4"; if [[ "$database" == "." ]]; then database=$(mysql_database_list) fi for name in $database; do file="$dumppath/$name.sql" $_cella_runas mysqldump \ $_cella_mysql_host \ $_cella_mysql_user \ $_cella_mysql_pass \ --comments \ --extended-insert \ --flush-logs \ --quick \ --routines \ --databases $name \ --result-file="$file" \ 1>>$_cella_log 2>>$_cella_err done _cella_runas= return 0 } export -f mysql_backup # # Gets a list of the MySQL Databases function mysql_database_list() { echo "show databases; " | $_cella_runas mysql \ $_cella_mysql_host \ $_cella_mysql_user \ $_cella_mysql_pass \ --batch \ --disable-pager \ --silent \ --skip-column-names \ |grep -v -e 'information_schema' } export -f mysql_database_list # # Backup PostgreSQL # @param $1 = source, "." for all on localhost, "$server/$database" or "$server/." # @param $2 = target directory # @param $3 = Username # @param $4 = Password function pgsql_backup() { hostname=$(echo "$1"|cut -d'/' -f1) database=$(echo "$1"|cut -d'/' -f2) if [[ "$hostname" == "$database" ]]; then hostname="" fi # Hostname/Database if [[ -n "$hostname" ]]; then _cella_pgsql_host="--host=$hostname" fi # Path dumppath=$2 if [[ ! -d "$dumppath" ]]; then mkdir -p "$dumppath" fi # User if [[ -n "$3" ]]; then _cella_pgsql_user="--username=$3" fi password=$4 # # # Export PGSQL Variables # # export PGHOST=$h # # export PGUSER=${args[4]:-postgres} # # export PGPASSWORD= # $_cella_runas psql \ # $_cella_pgsql_host \ # $_cella_pgsql_user \ # --command="\\du" > "$dumppath/user.tab" if [[ "$database" == "." ]]; then database=$(pgsql_database_list) fi for name in $database; do $_cella_runas pg_dump \ $_cella_pgsql_host \ $_cella_pgsql_user \ --blobs \ --format=custom \ --file="$dumppath/$name.pgd" \ "$name" \ 1>>$_cella_log 2>>$_cella_err done _cella_runas= return 0 } export -f pgsql_backup # # Get a List of the Databases function pgsql_database_list() { $_cella_runas psql \ $_cella_pgsql_host \ $_cella_pgsql_user \ --list \ --tuples-only \ --no-align \ --expanded \ |grep Name|cut -d'|' -f2|grep -v '^template' } export -f pgsql_database_list # # ldapbackup # @todo set SIZELIMIT 8000 in /etc/openldap/slapd.conf # @todo or use slapcat (which may be dangerous?) function slapd_backup() { source=$1 $_cella_runas ldapsearch # ldapsearch -L -D $BIND_USER -w $BIND_PASS -h $MASTERLDAP_IP -p 389 -b'dc=mydomain,dc=com' -s sub '(objectclass=*)' > $OUTPUT_FILE # http://supportex.net/2011/02/backup-restore-ldap-database/ # slapcat -o ldif-wrap=80 -v -l /home/backup/ldap.diff } # # Archive SVN with Hot Backup # @param $1 = Source, eg: "/opt/edoceo/svn/" # @param $2 = Target, eg: "/mnt/Raid1/Cella/" function svn_backup() { source=$1 target=$2 if [[ ! -d "$target" ]]; then $_cella_runas mkdir -p "$target" fi $_cella_runas svn-hot-backup \ --archive-type=gz \ --num-backups=3 \ "$source" \ "$target" \ 1>>$_cella_log 2>>$_cella_err _cella_runas= return 0 } export -f svn_backup # # Process Cella Options if [ $# == 0 ]; then cella_help fi for opt in $@ do case "${opt}" in update) wget -O- http://cdn.edoceo.com/bin/cella.sh > $0 ;; --debug|-x) set -o xtrace ;; --help|-h) cella_help ;; --verbose|-v) set -o verbose ;; --age=*) _cella_rdiff_age=${opt#*=} ;; --err=*) _cella_err=${opt#*=} ;; --log=*) _cella_log=${opt#*=} ;; # All Other Options Assumed to be Executable Scripts *) # Execute in a sub-shell if [[ -f "$opt" ]]; then _t0=$(date +%s) ( source "$opt" ) _t1=$(date +%s) # logger --id --stderr --tag cella "conf '$opt' took $(( $_t1 - $_t0 )) seconds" fi ;; esac done