Showing posts with label shell scripts. Show all posts
Showing posts with label shell scripts. Show all posts

Thursday, March 29, 2012

chkconfig script သို႕မဟုတ္ init script

ဟိုေန႕က client တစ္ခုက အင္ဂ်င္နီယာက သူဟာဟာသူေရးထားတဲ့ script တစ္ခုကို server boot time မွာ run ခ်င္လို႕တဲ့ လွမ္းေမးတယ္ ။ သူတို႕ က RHEL 6 သုံးေနတာပါ ။ အဲဒါနဲ႕ init script ေလးေရးျပီး init.d ထဲထဲ့ထားလိုက္လို႕ ျပန္ေျပာလိုက္တယ္။ ေနာက္ေန႕က် ေရးေပးပါတဲ့။ သူက ဘာ script run ခ်င္မွန္းမသိတာနဲ႕ template ပံုစံေလးေရးေပးလိုက္တယ္။

( Note: blogspot မွာ script ေရးျပရတာ ေတာ္ေတာ္ စိတ္ညစ္စရာ ေကာင္းတာပဲ syntax အကုန္ေပ်ာက္ျပီး left align ေတြျဖစ္ကုန္တယ္ )


#! /bin/bash
# (script) init script
###
# chkconfig: 235 35 55
# description: Starting ( your script ) at boot up

case "$1" in
start)
/path/to/your/script &
echo "(script) is starting"
;;
stop)
kill -9 `ps -ef | grep (script) | grep -v grep| cut -d" " -f6`
echo "(script) is stopping"
;;
*)
exit 1
echo "Usage : /sbin/service (script) {start|stop}"
esac

exit 0


(script) ဆိုတဲ့ ေနရာေလးေတြ မွာ ကိုယ့္ script နဲ႕ အစားထိုးပါလို႕ဆိုျပီး ေပးလိုက္တယ္ ။ အဆင္ေျပသြားတယ္တဲ့ ။ Init script က ဒီ syntax နဲ႕ပဲ အလုပ္လုပ္ပါတယ္ ။ ကိုယ့္ဟာကိုယ္ တျခား script တစ္ခုခုကို စခ်င္လည္း ဒီ template ကိုသုံးလို႕ရပါတယ္ ။ အေရးၾကီးတာ No.4 လိုင္းပါ ။ အဲမွာ chkconfig 235 35 55 လို႕ေပးထားပါတယ္ ။

အေရွ႕ဆုံးက 235 ဆိုတာက ဒီ script ကို run မဲ့ runlevel ေတြပါ ။ Runlevel ဆိုတာ ဘာလည္းမေသခ်ာရင္ ရွာဖတ္ၾကည့္ေစခ်င္ပါတယ္။ ပံုမွန္အားျဖင့္ 0 to 6 ရွိပါတယ္ ။
0 = shutdown ၊
6 = reboot ၊
1 = single user mode
2 = multi-user mode without networking
3 = multi-user mode with networking
4 = User-definable
5 = multi-user mode with networking + GUI


ဒီ init script မွာဆို လိုခ်င္တဲ့ service / script ကို runlevel 2 , 3 နဲ႕ 5 မွာပဲ စမယ္လို႕ ေျပာထားပါတယ္ ။

အေနာက္က 35 နဲ႕ 55 က script ကို boot up time မွာစမဲ့ priority နဲ႕ shutdown time မွာ kill မဲ့ priority ပါ။ /etc/rcx.d/ ထဲမွာ script ေတြကို S55httpd ၊ K55httpd ဆိုျပီး အေရွ႕မွာ Sxx ၊ Kxx ေတြနဲ႕ ရွိေလ့ရွိပါတယ္။ ဒါကဘာကို ေဖာ္ျပတာလည္းဆိုရင္ ၊ ဆိုၾကပါစို႕ rc3.d ထဲမွာ S10sshd နဲ႕ S55httpd ဆိုျပီးရွိတယ္ ။ ဒါဆို တကယ္လို႕ server က runlevel 3 ကို run တယ္ဆိုရင္ Inittab က rc3.d ထဲက start script ေတြကို အစီအစဥ္အလိုက္ စပါတယ္ ။ ဒီမွာဆို S10 ျဖစ္တဲ့ sshd က အရင္စပါလိမ့္မယ္ ၊ ေနာက္မွ S55 ျဖစ္တဲ့ httpd က စပါလိမ့္မယ္။ အဲေတာ့ ကိုယ့္ script ကို ေစာေစာစီးစီး စေစခ်င္ရင္ အဲမွာ 35 ေနရာမွာ နံပါတ္ေသးေသး ေပးရပါလိမ့္မယ္ ။ rcx.d ကို ဖြင့္ၾကည့္ရင္ ကိုယ့္ script က ဘယ္အခ်ိန္ေလာက္မွာ စရင္ အဆင္ေျပမလည္း စဥ္းစားလို႕ရမွာပါ။ အေနာက္က 55 က လည္း ထိုနည္းတူပါပဲ ။ Shutdown လုပ္တဲ့အခ်ိန္မွာ ေစာေစာ kill ေစခ်င္ရင္ နံပါတ္ေသးေသးေပးပါ။ ေနာက္ဆုံးမွ kill ေစခ်င္ရင္ 99 လို႕ေပးလိုက္ပါ။

ဒီ init script က သူ run ခ်င္တာကို root အေနနဲ႕ run ဖို႕ ေရးထားတာပါ ။ တကယ္လို႕ တျခား user အေနနဲ႕ run ခ်င္ရင္ လိုင္းနံပါတ္ 9 မွာ su ကိုသုံးရပါမယ္ ။ ဒါဆို ဒီလိုျဖစ္သြားမယ္

su username -c /path/to/your/script &


Stop လုပ္တဲ့ အပိုင္းကေတာ့ လြယ္လြယ္ကူကူ PID ကိုရွာျပီး kill လိုက္တာပဲ ေရးထားပါတယ္ ။

ျပီးရင္ေတာ့ ဒီ init script ေလးကို /etc/init.d/ ေအာက္ထဲမွာ သြားထားရပါမယ္။ testscript လို႕ filename ကိုေပးလိုက္တယ္ ဆိုပါေတာ့။ ျပီးရင္ ဒါကို executable ျဖစ္ေအာင္ ေပးရပါတယ္။ ဒီ command ကို႐ိုက္ပါ ။
# chmod +x /etc/init.d/testscript


ျပီးရင္ chkconfig မွာ register လုပ္ရပါတယ္ ။ /etc/init.d ေအာက္ထဲမွာရွိတိုင္း rcx.d မွာမရွိပါဘူး ။ အဲထဲကို သက္ဆိုင္ရာ S နံပါတ္ K နံပါတ္နဲ႕ ေရာက္ေအာင္က register ရပါတယ္ ။
# chkconfig --add testscript


အဲဒါျပီးရင္ ကိုယ့္ရဲ့ script က server bootup တိုင္းမွာ သူ့ဘာသာသူ start ေနပါလိမ့္မယ္

( Note : rcx.d ဆိုတာ nix နဲ႕ နဲနဲ ရင္းႏွီးရင္ သိပါတယ္။ /etc ေအာက္မွာ rc1.d ၊ rc2.d ဆိုျပီး rc5.d အထိရွိပါတယ္ ။ သက္ဆိုင္ရာ runlevel မွာ စတဲ့ service ေတြရဲ့ start script ၊ stop script ေတြက အဲဒီထဲမွာရွိပါတယ္ ။ )

Divinity

Sunday, June 13, 2010

Clean script ( shell scripting)

Google docs ထဲၾကည့္ရင္းနဲ႕ အရင္က Shell script တိုတိုေလး တစ္ခုကို post လုပ္ျပီး ေရးဖို႕ စိတ္ကူးရလို႕။ Analysing လိုလို post ေတြက ေလွ်ာက္သာေရးေနတာ ကိုယ့္ဟာကိုယ္လည္း ပ်င္းတယ္။

ဒီ script မ်ိဳးကို က်ေနာ္တို႕က clean script လို႕ေခၚပါတယ္။ တကယ္ အလုပ္လုပ္တာက process kill တာပါ။ တခ်ိဳ႕ service ေတြက start ရင္ပဲျဖစ္ျဖစ္ stop ရင္ပဲျဖစ္ျဖစ္ တဝက္တပ်က္မွာ ရပ္သြားတာမ်ိဳးရွိတတ္ပါတယ္။ ျပန္ start ရင္လည္း service က run ေနျပီလို႕ေျပာတယ္။ Process list ထဲမွာလည္းရွိတယ္။ Log ထဲမွာက error ၾကီးနဲ႕ access လုပ္လို႕မရဘူး။ တခါတေလ service port ေတာင္ မပြင့္လိုက္ဖူး။ Stop လုပ္လို႕လည္းမရေတာ့ဘူး။ လြယ္လြယ္ေျပာရင္ေတာ့ Hang သြားတာေပါ့။ ဒါဆို kill မွရေတာ့မယ္။ ဒါမ်ိဳးက Failover Cluster လိုမ်ိဳးမွာ သုံးေလ့ရွိပါတယ္။ တစ္ဖက္မွာ hang ေနရင္ kill လိုက္၊ ျပန္စၾကည့္ ၊ ထပ္ hang ရင္ ထပ္ kill ျပီး ေနာက္ server တစ္လုံးကို failover လုပ္သြား၊ admin ကို mail ေလးဘာေလးပို႕။ ( MySQL ဆို file access permission error ရွိရင္ အဲဒါမ်ိဳးျဖစ္တက္တယ္။ )

Service kill တာပဲ ကိုယ့္ဟာကိုယ္ ps ေလး႐ိုက္ျပီးၾကည့္ ၊ pid ေလးမွတ္ျပီး kill လိုက္႐ံုေပါ့။ ဒါက manual လုပ္မွ ျဖစ္မွာပါ။ Administrator တစ္ေယာက္က ဘယ္မွာ ဘာ hang ေနလည္း သိဖို႕ စိတ္တန္ခိုးရွိမွ ျဖစ္မယ္၊ မဟုတ္ရင္ သိလိုက္မွာ မဟုတ္ဖူး။ တစ္ခါတစ္ေလ ဒီ server ေတြကို Veritas Cluster တို႕ဘာတို႕လို Server and service monitor ေတြနဲ႕ monitor လုပ္ခိုင္းထားျပီး service status ကို သူ႕ဟာသူ စစ္ခိုင္းထားတာမ်ိဳး၊ လူကိုယ္တိုင္ manual လုပ္ရတာမ်ိဳး နည္းႏိုင္သမွ် နည္းေအာင္ လုပ္ခ်င္တာမ်ိဳးဆိုရင္ေတာ့ script ေလးေတြလိုျပီ။ Veritas က ဒီ serivce hang ေနမွန္းသိရင္ (ဒါကလည္း တျခား script တစ္ခုနဲ႕ စစ္တာမ်ိဳးပါ) clean script ကိုေခၚျပီး kill လိုက္ပါတယ္။ ျပီးမွ start script ကို ေခၚျပီး ျပန္ စတာေပါ့။

#!/bin/sh

pid=`/usr/bin/ps -ef | /usr/bin/grep mysqld | grep -v grep|awk -F' ' '{print $2}'`;

if test "$pid" = "" ; then
echo "Process is not Running";
else
echo "Killing process..."
kill -9 $pid;
fi


ဒီ script မွာ mysqld ကို ဥပမာ အေနနဲ႕ေပးထားပါတယ္။ Script ေလးကိုျပန္ၾကည့္ရေအာင္။

ပထမ line မွာ #!/bin/sh လို႕ေပးထားတာက Shell Env ကို sh shell လို႕သက္မွတ္တာပါ။ ဒီ script က bash shell မွာလည္း အလုပ္လုပ္ပါတယ္။

ဒုတိယ line က ဒီ script မွာ အဓိက အလုပ္လုပ္တယ့္ line ပါ။
pid=`/usr/bin/ps -ef | /usr/bin/grep mysqld | grep -v grep | awk -F' ' '{print $2}'`;


pid ဆိုတယ့္ variable တစ္ခုယူလိုက္ပါတယ္။ ဘာ type ျဖစ္ရမယ္လို႕ ၾကိဳသတ္မွတ္ေပးဖို႕မလိုပါဘူး။ pid ထဲကို value တစ္ခုထဲ့တယ့္ေနရာမွာ နည္းနည္းအေသးစိတ္ပါတယ္။ ေနာက္က command ေတြကိုအရင္စမ္းၾကည့္၊ လိုခ်င္တယ့္ result ရမွ ဒီline ကိုေရးတာေကာင္းပါတယ္။ #ps -ef | grep mysqld နဲ႕ MySQL service ရဲ့ process id ကိုၾကည့္လို႕ရပါတယ္။ ဒါေပမယ့္ -ef ရဲ့ ထုံးစံအရ၊ MySQL ရဲ့ pid အျပင္ အခု run လိုက္တယ့္ grep command ရဲ့ pid ပါျပေနတယ္။ ဒါဆို pid အပိုတစ္ခုပါေနတယ္။ ဒါဆိုမလိုအပ္တယ့္ grep ရဲ့ pid ကို ဖယ္ထုတ္မယ္။ grep -v grep ကိုသုံးပါတယ္။ grep -v က invert match လို႕ေခၚတယ့္ option ပါ။ grep -v grep လို႕ေပးလိုက္ေတာ့ grep ရဲ့ pid က လြဲရင္ လို႕ ဆိုလိုလိုက္တာပါ။ ဒါဆို mysqld တစ္လိုင္းထဲရျပီ။ ( တကယ္လို႕ တျခားမဆိုင္တာေတြရွိရင္လည္း ဖယ္ရပါလိမ့္မယ္။ ဒါမွမဟုတ္လည္း result ထဲက ေနာက္တစ္ခုကို ထပ္ grep လိုက္ေပါ့။ ) လိုခ်င္တာ တစ္လိုင္းထဲရျပီဆိုရင္ လိုခ်င္တယ့္ Process ID တစ္ခုထဲကို pid variable ထဲကို ထဲ့ဖို႕ လိုပါတယ္။ တစ္လိုင္းလုံးေပးလိုက္လို႕မရပါဘူး။ ဒီမွာ awk ကိုသုံးျပီး pattern filtering လုပ္ပါတယ္။ awk -F' ' ဆိုတာက awk ကိုသုံးျပီး output result ကို filed ေတြခြဲလိုက္တာပါ။ ဘာနဲ႕ ခြဲလည္းဆိုေတာ့ -F ဆိုတယ့္ Field separator နဲ႕ field ေတြကို space နဲ႕ခြဲထားတယ္လို႕ ေျပာလိုက္ပါတယ္။ -F ရဲ့ ေနာက္က quote ေလးႏွစ္ခုၾကားမွာ space တစ္ခ်က္ပါပါတယ္။ ေနာက္က '{print $2}' ဆိုတာကေတာ့ ခုနက space ေတြနဲ႕ခြဲထားတယ့္ထဲက ဒုတိယ field ကိုပဲျပပါလို႕ ေျပာတာပါ။ ဒါဆို Mysqld ရဲ့ process id တစ္လုံးထဲရပါျပီ။ အဲဒီ process id number ကို pid ဆိုတယ့္ variable ထဲကို ထည့္လိုက္ပါတယ္။

ေျပာစရာ က်န္ခဲ့တာက equal sign ေလးရဲ့ေနာက္က command execution တစ္ခုလုံးကို ` ` ႏွစ္ခုၾကားမွာေရးပါတယ္။ Keyboard မွာ 1 ေဘးကေကာင္ေလးေပါ့။ exec comand နဲ႕ ခက္ဆင္ဆင္တူပါတယ္။ ဒီ line မွာ Mysqld က run ေနရင္ mysqld ရဲ့ pid ကို output result အျဖစ္ pid variable ထဲထည့္လိုက္ျပီး ၊ run မေနဖူးဆိုရင္ ဘာ output မွမထြက္တယ့္အတြက္ pid variable က empty value ပဲ ဆက္ျဖစ္ေနပါလိမ့္မယ္။

ဒုတိယ line ကရလာတာကို မွ if .. else နဲ႕ ျပန္စစ္ျပီး အလုပ္လုပ္ပါျပီ။
if test "$pid" = "" ; then

if test နဲ႕စစ္ျပီး then ရဲ့ေနာက္က (ေအာက္က) line ေတြကို အလုပ္လုပ္ပါတယ္။ if test "$pid" = "" လို႕စစ္လိုက္တယ့္အရ $pid ထဲမွာ ဘာ value မွမရွိပဲ blank ျဖစ္ေနမယ္ဆိုရင္ ေအာက္ကလိုင္းျဖစ္တယ့္ echo ကိုအလုပ္လုပ္ပါတယ္။

else နဲ႕ တကယ္လို႕ pid variable မွာ value တစ္ခုခုရွိေနမယ္ ဆိုရင္ process kill ေၾကာင္း echo msg ေလးတစ္ေၾကာင္းေပးျပီး kill -9 $pid နဲ႕ pid variable ထဲမွာပါလာတယ့္ process id number ကို kill ပါတယ္။ ဒီမွာ process က hang ေနတာမို႕ -9 နဲ႕ မွရပါလိမ့္မယ္။

ဒီမွာ နည္းနည္း ထြန္႕စရာေလးေတြ ရွိေသးတယ္။ ps မွာ -ef option ကမ်က္စိေနာက္တယ္။ -ae နဲ႕ မရဖူးလားဆို ရပါတယ္။ print မွာ $1 ျဖစ္သြားပါလိမ့္မယ္။ Unix style နဲ႕ aux နဲ႕ဆိုရင္ေတာ့ $2 ပါပဲ။ ကိုယ့္ဟာကိုယ္ျပင္ေပါ့။ -ae က MySQL လိုမ်ိဳး process name ရွင္းမွ အဆင္ေျပပါတယ္။ Java လိုေကာင္ေတြဆိုရင္ Java ဆိုတယ့္ process name နဲ႕ပဲ ေခၚထားတယ့္ class ေပၚမွာမူတည္ျပီး မတူညီတယ့္ process ေတြျဖစ္တက္ပါတယ္။ အဲဒါမ်ိဳးဆို ps -ef နဲ႕ java ကို တစ္ခါ ၊ classname ကိုတစ္ခါ grep မွ လိုခ်င္တယ့္ process ကိုအတိအက်ရပါလိမ့္မယ္။

If test မွာလည္း "" နဲ႕ blank လို႕မစစ္ပဲ NULL ျဖစ္မျဖစ္စစ္ရင္လည္း ရပါတယ္။ Space ေလးေတြျဖဳတ္ေရးရပါလိမ့္မယ္။ Knowledge sharing သက္သက္ပါ။ က်ေနာ္လည္း shell scripting expert မဟုတ္လို႕ ဒီထက္လြယ္ကူတယ့္ နည္းလမ္းလည္း ရွိႏိုင္ပါတယ္။ သိရင္ ျပန္လာ share ပါ။ စိတ္ဝင္စားပါတယ္။ :D