User Tools

Site Tools


interessen:computer:pc_technik:backup

Table of Contents

Backup

Einige Zeit hat das Backup mit “rsync” gut funktioniert, aber ich habe mitr überlegt, dass ein einzelnes Backup bzw. das Backup auf eine einzelne Platte eventuell doch nicht so optimal ist. Daher habe ich mich ein wenig umgesehen wie man das besser machen kann ohne gleich das Backup-Script mehrmals mit verschiedenen Zielen aufzurufen.

Die Lösung war dann die Umstellung meiner derzeitigen gluster Konfiguration hin zu einer gespiegelten Konfiguration.

Damit hatte ich auch die Möglichkeit beim Backup gleichzeitig auf zwei (oder mehr) verschiedenen Server meine Backups zu schreiben.

Da ich das neue Script so flexibel wie möglich machen wollte habe ich mir überlegt, alle Parameter in ein extra File auszulagern. Ich habe wegen der einfachen Lesbarkeit -json als Format gewählt.

Backup-Script

Es sind noch viele “echo” drinn damit man beim manuellen starten des Scriptes sehen kann, was gerade passiert und wie die folgenden Kommandos dann zusammen gesetzt werden.

#!/bin/bash
#############################################################################
#                                                                           #
# backup script                                                             #
# Author : theta-my -> thomas@tuhol.de                                      #
#                                                                           #
# can run with different backup methods,                                    #
# please take a look in backup_<host>.jason file for further informations   #
#                                                                           #
# to make my work easier, i have all my urgent data located in one folder   #
# and mount this folder or sub folders to the right location in file system #
#                                                                           #
#############################################################################

setup()
{
	tstemp=`date +%Y%m%d%H%M`
	host=`hostname`
	
	# define definition file and check availability
	DATA_FILE=/opt/backup/backup_$host.json
	if [ ! -f $DATA_FILE ]
	then
		logger " <error> : definition file /opt/backup/backup_$host.json not reachable, check file location"
		exit
	fi
	
	WORK_DIR=`jq .work_dir $DATA_FILE|sed 's/\"//g'`/
	cd $WORK_DIR
	echo "working and running in : "$WORK_DIR
	MOUNT_FS=""
	message=""
	ERR_STOP=0
	ERR_COUNT=0
	ERR_HIGH_COUNT=0
	ERR_MEDIUM_COUNT=0
	ERR_LOW_COUNT=0
	LOG_DIR=`jq .log_dir $DATA_FILE|sed 's/\"//g'`
	LOG_FILE=$LOG_DIR/$tstemp.backup.log
	LOG_CHECK_FILE=$LOG_DIR/$tstemp.backup.check.log
}

error_check()
{
	echo "job 'error_check' is running"
	IGNOR=`jq .jobs.error_check.err_ignore $DATA_FILE|sed 's/\"//g'`
	echo "error to ignor : "$IGNOR

	HIGH=`jq .jobs.error_check.err_high $DATA_FILE|sed 's/\"//g'`
	MEDIUM=`jq .jobs.error_check.err_medium $DATA_FILE|sed 's/\"//g'`
	LOW=`jq .jobs.error_check.err_low $DATA_FILE|sed 's/\"//g'`

	for FILE in `cat $LOG_CHECK_FILE | grep '<f'|cut -d\/ -f2-`
	do
		echo "check line "$FILE
		if [[ $IGNOR = "" ]]
		then 
			error_check_sub
		else
			for TYPE in ${IGNOR[@]}
			do
				if ( ! $FILE| grep $TYPE )
				then
					error_check_sub
				fi
			done
		fi
	done
}

error_check_sub()
{
	if ( cat $LOG_FILE | grep $FILE )
	then
		echo "check line "$FILE
		for i in ${HIGH[@]}
		do
			if ( $FILE|grep $i )
			then
				(($ERR_HIGH_COUNT++))
			fi
		done
		
		for i in ${MEDIUM[@]}
		do
			if ( $FILE|grep $i )
			then
				(($ERR_MEDIUM_COUNT++))
			fi
		done
		
		for i in ${LOW[@]}
		do
			if ( $FILE|grep $i )
			then
				(($ERR_LOW_COUNT++))
			fi
		done

		(($ERR_COUNT++))
		echo $ERR_COUNT
	fi
}

messaging()
{
	echo "job 'messaging' is running, generate massage for syslog"
	if [ $ERR_COUNT -gt 0 ]
	then
		if [ $ERR_HIGH_COUNT -eq 0 ]
		then
			pre_massage=' <error>'
		else
			pre_message=' <warning>'
		fi
		message=$pre_message' : backup has '$ERR_COUNT' failures: '$ERR_HIGH_COUNT' high, '$ERR_MEDIUM_COUNT' medium and '$ERR_LOW_COUNT' low; check errorlog in '$LOG_DIR
		echo "backup has "$ERR_COUNT
	else
		message=' <info> : backup successfully completed'

		if [[ `jq .log_remove $DATA_FILE|sed 's/\"//g'` = "yes" ]]
		then
			rm $LOG_DIR/*
		fi
	fi
}

replicate()
{
	echo "job 'replicate' is running"
	TARGET_DIR=`jq .jobs.replicate.remote_folder $DATA_FILE|sed 's/\"//g'`
	REPL_OPT=`jq .jobs.replicate.repli_opt $DATA_FILE|sed 's/\"//g'`
	METHOD=`jq .jobs.replicate.method $DATA_FILE|sed 's/\"//g'`
	if [[ ! $REPL_OPT = "" ]]
	then
		if [[ $REPL_OPT = "local" ]]
		then
			DESTIN=$MOUNT_P/$TARGET_DIR
			PASSFILE=""
			if [ ! -d $DESTIN ]
			then
				echo $DESTIN" not exist, will create"
				mkdir $DESTIN
			fi
			DESTIN=$DESTIN/
			echo "local sync target "$DESTIN
		else
			SERVER=`jq .jobs.replicate.sync_server $DATA_FILE`
			if( ! ping -c 3  $SERVER > /dev/null )
			then
				(($ERR_STOP++))
				message="<info> : server "$SERVER" not reachable"
				break 
			fi
	
			USER=`jq .jobs.replicate.sync_user $DATA_FILE|sed 's/\"//g'`
			PASS_OPT=`jq .jobs.replicate.pass_option $DATA_FILE`
			DESTIN=$USER@$SERVER::/$MOUNT_P/$TARGET_DIR/
			echo "remote sync with "$DESTIN
		fi
	
		FOLDERS=`jq .jobs.replicate.sync_folders $DATA_FILE|sed 's/\"//g'`
		echo $FOLDERS
		
		date >> $LOG_FILE
		date >> $LOG_CHECK_FILE
		
		for DIR in ${FOLDERS[@]}
		do
			echo $DIR
			echo "run : "$METHOD `jq .jobs.replicate.run_options $DATA_FILE|sed 's/\"//g'` $DIR $DESTIN $PASS_OPT
			echo "{"$DIR"()" >> $LOG_FILE
			$METHOD `jq .jobs.replicate.run_options $DATA_FILE|sed 's/\"//g'` $DIR $DESTIN $PASS_OPT >> $LOG_FILE
			echo "{"$DIR"()" >> $LOG_CHECK_FILE
			$METHOD `jq .jobs.replicate.log_options $DATA_FILE|sed 's/\"//g'` $DIR $DESTIN $PASS_OPT >> $LOG_CHECK_FILE
			echo "}" >> $LOG_FILE
			echo "}" >> $LOG_CHECK_FILE
		done
		
		date >> $LOG_FILE
		date >> $LOG_CHECK_FILE
		error_check
	else
		(($ERR_STOP++))
		message=" <warning> : no method defined"
	fi
}

mount_fs()
{
	echo "job 'mount_fs' is running"
	# check if target host available
	TARGET_SRV=`jq .jobs.mount_fs.ping_target $DATA_FILE|sed 's/\"//g'`
	echo "check, if you'r in right location, try to ping "$TARGET_SRV
	MOUNT_P=`jq .jobs.mount_fs.mount_point $DATA_FILE|sed 's/\"//g'`
	if( ping -c 3  $TARGET_SRV > /dev/null )
	then	
		echo $TARGET_SRV" reachable, you'r in right location to backup"
		if [[ `jq .jobs.mount_fs.mount_def $DATA_FILE|sed 's/\"//g'` = "file" ]]
		then
			echo "mount "`jq .jobs.mount_fs.mount_opt $DATA_FILE|sed 's/\"//g'` `jq .jobs.mount_fs.mount_file $DATA_FILE|sed 's/\"//g'` $MOUNT_P
			mount `jq .jobs.mount_fs.mount_opt $DATA_FILE|sed 's/\"//g'` `jq .jobs.mount_fs.mount_file $DATA_FILE|sed 's/\"//g'` $MOUNT_P
		else
			CONNECT=`jq .jobs.mount_fs.mount_srv $DATA_FILE|sed 's/\"//g'`:`jq .jobs.mount_fs.mount_share $DATA_FILE|sed 's/\"//g'`
			echo "mount "`jq .jobs.mount_fs.mount_opt $DATA_FILE|sed 's/\"//g'` $CONNECT $MOUNT_P
			mount `jq .jobs.mount_fs.mount_opt $DATA_FILE|sed 's/\"//g'` $CONNECT $MOUNT_P
		fi
		sleep 10 # be sure mount is completed or timed out
		if ( mount | grep $MOUNT_P > /dev/null )
		then
			MOUNT_FS=`jq .jobs.mount_fs.mount_point $DATA_FILE|sed 's/\"//g'`
			echo "umount "$MOUNT_FS" needed"
		else
			(($ERR_STOP++))
			message=" <warning> : Can not mount backup target volume"
		fi
	else
		(($ERR_STOP++))
		message=" <info> : "$TARGET_SRV" not reachable, server down or you are not at right location"	
	fi
}

# master function
main()
{
	# select job sequence
	
	SEQUENCE=`jq .job_seq $DATA_FILE|sed 's/\"//g'`
	echo "job sequence are : "$SEQUENCE
	
	if [[ $SEQUENCE = "" ]]
	then
		message=" <info> no jobs defined"
	else
		for JOB in ${SEQUENCE[@]}
		do
			if ( echo $JOB | grep add_tasks )
			then
				SUB_TASK=${JOB##*.}
				TARGET=$WORK_DIR`jq .jobs.add_tasks.$SUB_TASK.folder $DATA_FILE|sed 's/\"//g'`/
				echo "sub task target "$TARGET
				echo "run sub task : "`jq .jobs.$JOB.task $DATA_FILE|sed 's/\"//g'` $TARGET
				`jq .jobs.$JOB.task $DATA_FILE|sed 's/\"//g'` $TARGET
			else
				echo "run main job : "$JOB
				$JOB
			fi
			if [[ $ERR_STOP -gt 0 ]]
			then
				logger $message
				exit
			fi
		done
	fi
	
	echo "clean up"
	
	if [[ ! $MOUNT_FS = "" ]]
	then
		echo "umount "$MOUNT_FS
		umount $MOUNT_FS
	fi
	
	logger $message
}

# don't change sequence below
setup
main
exit

Parameter-File

Das dazu gehörende ParameterFile sieht dann so aus bei mir:

{
	"description": "json-file to backup and restore per backup-script",
	"work_dir":"/data",
	"log_dir":"/data/backuplog",
	"log_remove":"yes",	
	"job_seq":"mount_fs add_tasks.backup_opt replicate error_check messaging",
	"jobs":
	{
		"mount_fs":
		{
			"@":"'ping_target' is used to verify location; 'mount_def' can be 'file' or 'server'; in case of 'file', 'mount_file' needed",		
			"ping_target":"192.168.2.1",
			"mount_def":"file",
			"mount_opt":"-t glusterfs",
			"mount_srv":"<file server>",
			"mount_share":"<file server share>",
			"@":"'mount_file' describe a method to connect to a server and his share(s), 'mount_srv' and 'mount_share' not needed in this case",
			"mount_file":"/etc/glusterfs/gluster1.vol",
			"mount_point":"/gluster"
		},
		"replicate":
		{
			"@":"'repli_opt' can be 'local' or 'remote', 'remote' needs 'pass_option', 'sync_server' and 'sync_user'",		
			"repli_opt":"local",
			"@":"only rsync implemented yet, can try scp, but auth method must implemented by your self; use 'AX' to safe links",
			"method":"rsync",
		   "run_options":"-avh -partial",
	   	"log_options":"-avhn -partial",
			"@":"pass_option : file content format 'username:password'",
			"pass_option":"--password-file=<file location>",
			"sync_server":"<rsyncd server>",
			"sync_user":"<username>",
			"@":"if absolute path used in 'sync_folders', not 'work_dir' needed",
			"sync_folders":"Carrier Closed Documentation Downloads notes privat Projekts Proposals transcripts backup transfer",
			"@":"'remote_folder' means the backup folder at the target file system",
			"remote_folder":"Arbeit"
		},
		"error_check":
		{
			"@":"'err_ignore' means witch files or search words can be ignore in error log or errors at backup this files are normal (i.e. log-files)",
			"err_ignore":"",
			"@":"error level definitions",
			"err_high":"",
			"err_medium":"notes",
			"err_low":""
		},
		"messaging":"<no further parameter needed, all included in backup script>",
		"add_tasks":
		{
			"<task name>":
			{
				"folder":"<target folder for task>",
				"task":"<can be external(!) script or command, no sub routine in backup script>"
			},
			"backup_db":
			{
				"folder":"mysql_backup",
				"task":"mysqldump -u root --password=<PASSWORD> --all-databases > $TARGET"
			},
			"backup_opt":
			{
				"folder":"backup",
				"task":"cp -r /opt/backup/*"
			}
		}
	}
}

Die Jobs “mount_fs” und “replicate” sind als feste Optionen, siehe “job_seq” (Job Sequence), fertig definierte Schritte im BackupScript. Wobei auch “mount_fs” nur eine Option ist. Ich habe bei mir “mount_fs” gewählt, damit ich bei der Replikation keine Authentifizierung benötige und auch gleichzeitig auf zwei verschiedene Platten, bei mir zwei Server, schreiben kann. Wenn also bei mir ein Server, wegen was auch immer, nicht zur Verfügung steht, dann kann ich trotzdem mein Backup machen.

“add_tasks” sind frei definierbare zusätzliche Aufgaben deren Auführungszeitpunkt in “job_seq” definiert wird.

interessen/computer/pc_technik/backup.txt · Last modified: 2015/02/15 11:54 by tomtom