Проблематики

Friday, August 28, 2009

Как да си направим backup на диска под Линукс

Въпреки, че хардовете в днешно време са доста надеждни (поне на мен лично не ми е горял хард все още), не е зле човек да се потдотви и да си прави бакъпи редовно.
Понеже основната ми машинка която ползвам за SCM, Continuous integration, Issue trackig и т.н. е под линукс, затова реших да си напиша няколко скриптчета с които да си правя бакъпите. Изискванията ми не са кой знае какви - просто трябва да мога да си възтановя SCM и issue tracking даните без загуби и много труд. При евентуален срив и загуба на хард не очаквам да мога да възтановя цялата система. Пък и какъв е смисълът? Така никога няма да седна да инсталирам нова версия на софтуера! Всъщност от тази гледна точка сривовете са даже нещо много полезно... помагат ти да си разчистиш старите данни и боклуци, които са се насъбрали с години, кара те да качиш нови програмки и т.н. :-D Просто трябва да се случват в подходящ момент :-) когато имаш достатъчно време да си сетъпнеш нова система!...
Та да се върнем на въпроса - скриптът за бакъп трябва да може да копира някои директории, да ги архивира и да пази копия на тях. Също така е хубаво да може да се следи и история...случайно, ако се прецакат някакви настройки да могат да се проверят кога са променени, и да се възтановят правилните конфигурации. Та скрипта трябва да може да пази архив на старите бекъпи. В основата на всичко е rsync, която се използва за създаване на самите файлове. За да сработи скрипта трябва да се създаде една директория /etc/backup където са всички конфигурации включително и самият скрипт:

#!/bin/sh

VERBOSE=0
SCOPE=""
CONFIG="/etc/backup/backup.conf"

# Outputs the help message how to use the script
print_help()
{
echo "Usage: backup [-v | --verbose] <-s | --scope> " >&2
echo " -v or --verbose switch verbose mode on" >&2
echo " -s or --scope reads the list of directories to backup for " >&2
echo " the from the /etc/backup.conf " >&2
}

# Parses the passed command line and defines the backup scope, verbose mode, etc.
parse_command_line()
{
PREV_SCOPE=0
for p in "$@"; do
if [ $PREV_SCOPE -eq 1 ]; then
SCOPE=$p
PREV_SCOPE=0
else
if [ '--verbose' == $p -o '-v' == $p ]; then
VERBOSE=1
fi

if [ '--scope' == $p -o '-s' == $p ]; then
PREV_SCOPE=1
fi
fi
done
}

# Outputs message to the console if the verbose mode is selected
print()
{
if [ $VERBOSE -eq 1 ]; then
echo "$1"
fi
}


read_configuration()
{
# @author Michael Klier
match=0

while read line; do
# skip comments
[[ ${line:0:1} == "#" ]] && continue

# skip empty lines
[[ -z "$line" ]] && continue

# still no match? lets check again
if [ $match == 0 ]; then

# do we have an opening tag ?
if [[ ${line:$((${#line}-1))} == "{" ]]; then

# strip "{"
group=${line:0:$((${#line}-1))}
# strip whitespace
group=${group// /}

# do we have a match ?
if [[ "$group" == "$1" ]]; then
match=1
continue
fi

continue
fi

# found closing tag after config was read - exit loop
elif [[ ${line:0} == "}" && $match == 1 ]]; then
break

# got a config line eval it
else
eval $line
fi

done < "$CONFIG"
}


#
#
# The main script starts here
#
#

START_TIME=`date +%s`

# Parse the command line parameters
parse_command_line $@

if [ -z $SCOPE ]; then
print_help
echo $"Please enter the name of the backup scope" >&2
exit 1
fi

# Read LIST variable from the configuration file
read_configuration $SCOPE

# Example how the LIST variable should looks like
# LIST="etc root usr home var"

# Waits at 1 seconds, so if the user starts the script too fast the TIME_STAMP directory will be different
sleep 1

BACKUP_DIR="/backup/$SCOPE"

# Output the configuration information
print "Backup scope: $SCOPE"
print "Backup directory list: $LIST"
print "Exclude file: $EXCLUDE_FILE"
print "Backup dir is $BACKUP_DIR"

# Creates the backup directory
if [ ! -d $BACKUP_DIR ]; then
mkdir $BACKUP_DIR
fi

#
#
# Rotate backups, so we keep only the last 100
#
#

# Maximum number of backups to keep
maxInd=20

# Gets the oldest backup canonical path (it is a symbolic link to a time-stamped tar file)
REAL_PATH=`readlink -f $BACKUP_DIR/b.$maxInd.tar.gz`

# Remove the oldest backup
if [ -e $REAL_PATH ]; then
print "Removing tar file $REAL_PATH"
rm -rf $REAL_PATH
fi

# Remove the symbolic link
rm -rf $BACKUP_DIR/b.$maxInd.tar.gz


# Rotate backups from $ind to $ind+1
for ((ind = $maxInd-1; ind >= 0; ind--)); do
let nextInd=$ind+1
if [ -e $BACKUP_DIR/b.$ind.tar.gz ]; then
print "Rotating $BACKUP_DIR/b.$ind.tar.gz to $BACKUP_DIR/b.$nextInd.tar.gz"
mv $BACKUP_DIR/b.$ind.tar.gz $BACKUP_DIR/b.$nextInd.tar.gz
fi
done

# Delete the first backup (it must already be rotated, but just to be sure that the file doesn't exists)
rm -f $BACKUP_DIR/b.0.tar.gz

# Generate new timestamp for the new backup
TIME_STAMP=`date "+%F_%H-%M-%S"`

# Create the backup folder using the timestamp
mkdir $BACKUP_DIR/$TIME_STAMP

# Backup all files in the backup-list
for d in $LIST; do
print "Backuping /$d/ to $BACKUP_DIR/$TIME_STAMP/$d/"
mkdir -p $BACKUP_DIR/$TIME_STAMP/$d/
if [ $VERBOSE -eq 1 ]; then
rsync -vv -a --delete --exclude-from=$EXCLUDE_FILE /$d/ $BACKUP_DIR/$TIME_STAMP/$d/
else
rsync -a --delete --exclude-from=$EXCLUDE_FILE /$d/ $BACKUP_DIR/$TIME_STAMP/$d/
fi


done

# Go to the backup directory, so we could tar the content
pushd $BACKUP_DIR/$TIME_STAMP > /dev/null

# Archive the entire directory into single tar file
tar -c -z -f $BACKUP_DIR/$TIME_STAMP.tar.gz .

# Restore the current directory
popd > /dev/null

# Remove the backup directory
rm -rf $BACKUP_DIR/$TIME_STAMP

# Create a symbolic link to the directory
ln -s $BACKUP_DIR/$TIME_STAMP.tar.gz $BACKUP_DIR/b.0.tar.gz

FINISH_TIME=`date +%s`

FILE_SIZE=`ls -lrt $BACKUP_DIR/$TIME_STAMP.tar.gz | awk '{print $5}'`

printf "Completed! Execution time: $((FINISH_TIME - START_TIME)) seconds. Backup file size: $FILE_SIZE bytes."
printf "\n"




И така този скрипт се ползва по следния начин:
/etc/backup -s SCOPE_NAME

SCOPE_NAME се чете от конфигурационият файл /etc/backup.conf в който се описват кои директории да се копират. Ето и примерен такъв:
#
# In order to define a new scope of backup items uncomment following lines
#
#
#
# scope_name {
# LIST="etc root usr home var"
# EXCLUDE_FILE="/etc/backup/backup.excludes"
# }
#
# No leading ot trailing / in the directory names.
# The directories are sub directories of the /


weekly {
LIST="etc root usr home var"
EXCLUDE_FILE="/etc/backup/backup.excludes"
}

daily {
LIST="etc usr/red5/conf usr/red5/webapps usr/share/tomcat6/conf usr/share/tomcat6/webapps var/svn var/trac"
EXCLUDE_FILE="/etc/backup/backup.excludes"
}


Всеки scope си има списък от директории (LIST) и EXCLUDE_FILE в който се описват, коит файлове от тези директории да се пропуснат. Примерен backup.excludes:
#Excluding subdirs from /usr/

/bin/***
/java/***
/games/***
/kerberos/***
/sbin/***
/libexec/***
/lib/***
/tmp
/tmp/***
/include/***

# Excluding subdirs from /var/

/tmp/***


Така целият скрипт очаква, че ще има директория /backup (която е добре да моунтната на друг хард диск)

Хубаво е да се направят и cron task-ове които да правят дневен или седмичен бекъп.
Ето няколко примерни такива:

/etc/cron.daily/backup_daily
#!/bin/bash

TIME_STAMP=`date "+%F_%H-%M-%S"`

echo "Starting daily backup $TIME_STAMP" > /var/log/backup/$TIME_STAMP.log

/usr/bin/backup --verbose --scope daily > /var/log/backup/$TIME_STAMP.log 2> /var/log/backup/$TIME_STAMP.err



/etc/cron.weekly/backup_weekly
#!/bin/bash

TIME_STAMP=`date "+%F_%H-%M-%S"`

echo "Starting weekly backup $TIME_STAMP" > /var/log/backup/$TIME_STAMP.log

/usr/bin/backup --verbose --scope weekly > /var/log/backup/$TIME_STAMP.log 2> /var/log/backup/$TIME_STAMP.err



И така това е целият скрипт. Успех!

~Киро :-)

Many thanks to Michael Klier for his article
Parsing Simple Config Files In Bash

Labels:

Thursday, January 08, 2009

Red5 service за Линукс

Red5 е едно много хубаво сървърче за флаш. Инсталацията му под Windows е елементарна - има си setup.exe, което прави всичко. Под линукс обаче нещата не са толкова лесни - разархивираш tar файл, слагаш на необходимото място, инсталираш Sun-ска Java и т.н. Има доста форуми по въпроса. Единствения проблем е, ако трябва Red5 да се пуска като service. За Fedora 10 това се прави по следния начин:
1) добавя се един файл /etc/init.d/red5
2) chmod a+rx /etc/init.d/red5
3) съдържанието му е:



#! /bin/sh
#
# red5
#
# chkconfig: - 80 20
#
# Author: Kiril Arabadzhiyski
#
### BEGIN INIT INFO
# Provides: red5
# Required-Start: $network $syslog
# Required-Stop: $network $syslog
# Default-Start:
# Default-Stop:
# Description: Red5 - Open Source Flash Server
# Short-Description: start and stop red5
### END INIT INFO
#
# File location: /etc/init.d/red5
#
#
RED5_DIR=/usr/red5
test -x $RED5_DIR/red5.sh || exit 5

RED5_USER=red5
RED5_LOG_DIR=/var/log/red5

STDERR_LOG=$RED5_LOG_DIR/stderr.log
STDOUT_LOG=$RED5_LOG_DIR/stdout.log

if [ -r /lib/lsb/init-functions ]; then
. /lib/lsb/init-functions
else
exit 1
fi

function startCmdExec() {
su -s /bin/bash -c "${RED5_DIR}/red5.sh >> ${STDOUT_LOG} 2>> ${STDERR_LOG} &" ${RED5_USER}
}

function stopCmdExec() {
su -s /bin/bash -c "${RED5_DIR}/red5-shutdown.sh > /dev/null 2> /dev/null &" ${RED5_USER}
}

function start() {
echo -n "Starting Red5:"
cd $RED5_DIR

pid="$(pgrep -u ${RED5_USER} -G ${RED5_USER} java)"
if [ -z "$pid" ]; then
startCmdExec
sleep 2
pid="$(pgrep -u ${RED5_USER} -G ${RED5_USER} java)"
fi

if [ -n "$pid" ]; then
log_success_msg
else
log_failure_msg
fi
}



function stop() {
echo -n "Stopping Red5:"
echo -n " "
cd $RED5_DIR
stopCmdExec
sleep 5
pid="$(pgrep -u ${RED5_USER} -G ${RED5_USER} java)"
if [ -z "$pid" ]; then
log_success_msg
else
log_failure_msg
fi
}

function killIt() {
echo -n "Killing Red5:"
echo -n " "
su -s /bin/bash -c "killall -q -u ${RED5_USER} java" ${RED5_USER}
sleep 2
pid="$(pgrep -u ${RED5_USER} -G ${RED5_USER} java)"
if [ -z "$pid" ]; then
log_success_msg
else
log_failure_msg
fi
}

function status() {
pid="$(pgrep -u ${RED5_USER} -G ${RED5_USER} java)"
if [ -n "$pid" ]; then
echo "Red5 (pid ${pid}) is running..."
RETVAL="0"
else
echo "Red5 is stopped"
fi
}

function restart() {
stop
pid="$(pgrep -u ${RED5_USER} -G ${RED5_USER} java)"
if [ -n "$pid" ]; then
killIt
fi
start
}

case "$1" in
start)
start
;;
stop)
stop
;;
kill)
killIt
;;
restart)
restart
;;
status)
status
;;
esac



4) chkconfig --add red5
5) chkconfig red5 on
6) service red5 start

Ха честито!

Monday, March 03, 2008

Nero Direct show filters

Както всички знаем Nero беше една много добра програмка за печене на дискове. Клоючовата дума тук е беше. Незнам какво си мислят момчетата от Nero AG, но тази програмка стана твърде enterprise. Имат включени разни DirectShow филтри който създават един милион проблеми. Ето и един лесен начин да бъдат изключени - един batch файл който трябва да бъде стартиран.

@echo Unregistering nero burning rom filters
cd \Program Files\Common Files\Ahead\DSFilter
regsvr32 /u NDParser.ax
regsvr32 /u NeAudio.ax
regsvr32 /u NeFileSrc.ax
regsvr32 /u NeQTDec.ax
regsvr32 /u NeRender.ax
regsvr32 /u NeVideo.ax

Sunday, February 17, 2008

Windows service

Незнам дали на някого му се е налагало да ползва windows services или още повече да подава на съответния сървис command line parameters, но това си е голяма главоблъсканица.
Интересното е, че има някакъв key HKLM\SYSTEM\CurrentControlSet\Services\service_name\Parameters който не е ясно за какво е..но определено не е за command line параметрите. Истинските command line параметрите се подават от

HKLM\SYSTEM\CurrentControlSet\Services\service_name и ImagePath = "path_to_exe command_line_parameters "

Най-добрия пример е:
HKLM\SYSTEM\CurrentControlSet\Services\EventSystem

За да се изтестват параметрите може да се ползва Service MMC GUI-to, като се щтракне с десния бутон върху сървиса и се появява едно прозорче и отдолу има "Start parameters". Те обаче са само за текущото пускане, и не се запазват.

Monday, July 30, 2007

BEA WebLogic 10 под Fedora

Известно време се мъчих да подкарам Tomcat под Fedora 7..той си работеше ма аз нещо барнах и сега трябва бая да задълбая, за да го оправя. Пък и нещо не ми се занимава :-) Затова реших радикално проблема... взех че качих BEA WebLogic. Честно казано бях потресен колко лесно стана всичко... свалих един 700Mb-тов bin файл и само го пуснах... оправих директорията в която да се инталира и всичко мина като по-вода (next, next,next,next, finish)
Въпреки, че BEA имат официален съпорт само за RedHat linux, явно нямат проблеми продуктите им да работят и под Fedora 7 :-) Още разучавам точно какво инсталирах, ама май ще бъде интересно. Чудя се има ли някаква база отдолу, или е само jee server... нещо ме мързи да чета, както и да е, ще го разгледам по-подробно тия дни, че трябва да пиша и дипломна работа. Може би ще го ползвам за да ми хоства jsp-тата :-)
Направо съм удивен, колко лесно го инсталирах.. бях се подготвил за няколко часова борба с хиляда скрипт хака и разни страни exception-и - все пак бях изтеглил версия за Redhat, а не за Fedora... обаче се оказа че съм приключил за 10 мин. :-) Много се кефя!

Wednesday, June 06, 2007

Fedora 7

Ми освен да попиша малко за моя досег до новата Fedora 7. Общо взето бях може би един от първите които си я свалиха и качиха....даже БГ мирорите още я нямаха та я свалях от някви мирори в Европа...бая чакане си падна. Първите ми впечатления бяха: брех много fancy шаренийка ала бала... Инсталирането беше супер лесно всичко си детектна ок. След това гледам какъв софтуерм има.... и понеже нали съм си лаком реших да инсталирам всичко де що има като цъкалка :-) Е почахак около 2 часа да се download-не всичко за да получа великия всичко обяснвящ надпи...package xxxxx is not verified... Уау! Нали уж от официялния сайт инсталирам...Я един рестарт и да пробвам пак...все пак може да има някъв скрипт който не се е пуснал след първия рестарт веднага след инсталацията...знам ли.. Още 2 часа и пак същата грешка. Явно нещо има...деселектирам проблемния пакет и си мисля това сигурно е нещо недогледано на всеки му се случва....още 2 часа и бамм...същата грешка със друг пакет! Брех м*** му. Нали уж 4 фази на тестване и незнам си кво още. Тоя път не ми се чакаше пак 2 часа за това малко по-малко селектирани пакети и да пробваме пак...почнаха да гърмят един по един ...на 10тия се отказах. Гоогълнах половин час и гледам има няква опция на yum нещо като pgp check или нещо такова...явно тука се крие разковничето...сложих го на 0 в кофигурацията на yum и поне взеха че се инсталираха част от пакетите. Викам си щом на тест пц-то се инстална, да взема да пробвам и на лаптопа...той и е с 6-тицата да взема да го ъпгрейдна...да ама не.....детектна старта инсталация почна да анализира пакетите и каза "package %s ......" debug / restart....еми явно ще си остана със 6тицата.... а пък F8 трябва да има повечко тестване !

Wednesday, May 09, 2007

В дебрите на DirectShow или как да ползваме ISampleGrabber

Днеска за пореден път се сблъсках с добре структурираната и позотворна информация за DirectShow. Целта беше да ползвам ISampleGrabber филтърът за да направя няколко картинки от филмче. Example-и има много за това... обаче тайната как да ги компилираш я няма абсолютно никъде. Проблема е, че освен стандартното PlatformSDK трябва и DirectX SDK заради един header файл. След това обаче се набозват някакви недекларирани макроси и става яко мазало. Грешката която се получава е:

...mmstream.h(332) : error C2061: syntax error : identifier '__RPC__deref_out_opt'"
...mmstream.h(335) : error C2061: syntax error : identifier '__RPC__out'
...mmstream.h(339) : error C2061: syntax error : identifier '__RPC__in_opt'

и така още около 102 пъти :-)

В крайна сметка печелившата комбинация от include-и е следната:

rpcsal.h
dxtrans.h
qedit.h


Първият rpcsal.h е най-важен за тези макроси.