Pages

Saturday, 15 December 2012

Perl Script အေၿခခံ

Unix/Linux Admin ေတြအေနနဲ ့Shell Script တစ္ခုတည္းနဲ ့မလံုေလာက္ပါဘူး။ တခ်ိဳ ့Automation Script ေတြမွာ Perl, Python,  Awk အစရိွသၿဖင့္ တၿခား Programming Language ေတြ ေရာၿပီးအသံုးၿပဳရတာမ်ိဳးေတြရိွပါတယ္။ အခုေအာက္မွာ နမူနာေပးထားတာ ကေတာ့ က်ေနာ္ေရးထားတဲ့ Perl Script တခုၿဖစ္ပါတယ္။ အကုန္လံုးကို Perl command ေတြခ်ည္း သံုးထားတာ မဟုတ္ဘဲ Shell command ေတြကိုပါ ေရာသံုးထားပါတယ္။ scp process တို ့ unzip လုပ္တဲ့ေနရာတို ့မွာပါ။ unzip တို ့scp တို ့ကို Perl command ေတြခ်ည္းသံုးခ်င္ရင္ သက္ဆိုင္ရာ Perl Module ေတြ install လုပ္ရမွာၿဖစ္လို ့ အခုလိုမ်ိဳး shell command ေတြကိုသံုးထားတာပါ။

အခု script ကေတာ့ java web application တခုကို svn server ကေန copy ကူးၿပီး deploy လုပ္တဲ့ script ၿဖစ္ပါတယ္။ Deploy လုပ္မယ့္ file ေပၚမူတည္ၿပီး statement ေတြကို ထပ္ထည့္သြားလို ့ရတယ္။ 
ေအာက္က ဖိုင္မွာေတာ့ Deploy လုပ္မယ့္ file တခုတည္းအေနနဲ ့ၿပထားတယ္။


1:  #!/usr/bin/perl  
2:  # Deployment Script --WH (UPDATED 14NOV2012)  
3:  # Define the Directory Path below.  
4:  use File::Path;  
5:  $target = "/opt/weblogic/tmp";  
6:  $host = 'root@svn-host-ip:';  
7:  $checkout = "/opt/checkout/";  
8:  $today = `date '+%Y%m%d'`;  
9:  $appdir = "/opt/weblogic/deploy/ROOT";  
10: sub process_scp();  
11: sub extract_file();  
12: sub menu();  
13: sub do_exit();  
14: system ('clear');  
15: menu ();  
16: sub menu() {  
17: print <<"MENU";  
18: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
19:    Deploy script $today  
20:           1.Web Application Deploy  
21:           2.Exit  
22:    Choose which number you want to deploy  
23: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
24: MENU  
25: $number = <>;  
26: chomp ($number);  
27: if ($number eq "1") {  
28:      unlink(<$target/ROOT*>);  
29:      &process_scp("ROOT*");  
30:      extract_file();  
31:  } elsif ($number eq "2") {  
32:       do_exit();  
33:  } else {  
34:      menu();  
35:      print "Please enter the valid input\n";  
36:  }  
37:  }  
38:  sub process_scp() {  
39:  system ('scp ' . "$host" . "$checkout" . "@_" . " $target");  
40:  print "Copied @_ to $target\n";  
41:  }  
42:  sub extract_file() {  
43:  for ($number) {  
44:  if (($number) eq "1") {  
45:  print "Deploying Web Application\n";  
46:  rmtree([$appdir]);  
47:  mkdir $appdir;  
48:  system ('unzip' . " $target/ROOT* " . ' -d ' . $appdir);  
49:  print "Web Application Deployed!\n";  
50:  menu();  
51:  } else {  
52:  print "invalid input!\n";  
53:  menu();  
54:  }  
55:  }  
56:  }  
57:  sub do_exit(){  
58:  print "Exiting...\n";  
59:  return;  
60:  } 


Line နံပါတ္ ၁ ကေတာ့ perl နဲ ့run မယ့္ script ဆိုၿပီးေၿပာထားတာပါ။
Line နံပါတ္ ၂ နဲ ့ ၃ ကေတာ့ comment ပါ။
Line နံပါတ္ ၄ က File::Path ဆိုတဲ့ Module ကိုသံုးမယ္ဆိုၿပီး ေၿပာထားတာပါ။
Line နံပါတ္ ၅ ကေန ၉ အထိက variables ေတြ ေၾကၿငာထားတာပါ။
Line နံပါတ္ ၁၀ ကေန ၁၃ အထိက sub routines ေတြေၾကၿငာထားတာပါ။
Line နံပါတ္ ၁၄ ကေတာ့ system command ၿဖစ္ၿပီး screen ေပၚက cache ေတြကို clear လုပ္မွာၿဖစ္ပါတယ္။
Line နံပါတ္ ၁၅ ကေတာ့ menu ဆိုတဲ့ sub routine ကို သံုးမယ္လို ့ေၿပာထားတာပါ။
Line နံပါတ္ ၁၆ ကေန ၃၇ ထိက menu ဆိုတဲ့ sub routine.
Line နံပါတ္ ၁၇ ကေန ၂၄ ထိက  MENU ကို print ထုတ္တာပါ။
Line နံပါတ္ ၂၅ က User ရိုက္ထည့္မယ့္ နံပါတ္ကို $number ဆိုတဲ့ variable အၿဖစ္သတ္မွတ္ေပးတာပါ။
Line နံပါတ္ ၂၆ ကေတာ့ လက္ခံထားတဲ့ input ကေန newline character ေတြကိုဖယ္ထုတ္ေပးတာပါ။
Line နံပါတ္ ၂၇ ကေန ၃၆ ထိကေတာ့ if else statement ပါ။
input က 1 ၿဖစ္ခဲ့ရင္ line နံပါတ္ ၂၈ ၊ ၂၉ ၊ ၃၀ တို ့ကို execute လုပ္ပါမယ္။
Line နံပါတ္ ၂၈ ကေတာ့ ဖိုင္ဖ်က္တာပါ။ copy လုပ္မဲ့ destination မွာ version အေဟာင္းနဲ ့ဖိုင္ရိွခဲ့ရင္ ၾကိဳဖ်က္ထားတာပါ။
extract လုပ္ရင္ wildcard name နဲ ့လုပ္မွာၿဖစ္လို ့ ဖိုင္ ၂ ဖိုင္ၿဖစ္ေနရင္ error ၿဖစ္သြားနို္င္လို ့ပါ။
Line နံပါတ္ ၂၉ ကေတာ့ process_scp ဆိုတဲ့ sub routine ကို ROOT* ဆိုတဲ့ wildcard file name argument နဲ ့ execute လုပ္မွာပါ။
Line နံပါတ္ ၃၀ ကေတာ့ extract_file ဆိုတဲ့ sub routine ကို execute လုပ္မွာပါ။
Line နံပါတ္ ၃၁ မွာေတာ့ အကယ္၍ input က 2 ၿဖစ္ခဲ့ရင္ Line နံပါတ္ ၃၂ မွာေရးထားတဲ့ အတိုင္း do_exit ဆိုတဲ့ sub routine ကို execute လုပ္မွာပါ။
Line နံပါတ္ ၃၃ မွာေတာ့ အကယ္၍ input က 1 သို ့မဟုတ္ 2 မဟုတ္ဘူး ဆိုရင္ Line နံပါတ္ ၃၄ မွာေရးထားတဲ့အတိုင္း menu ဆိုတဲ့ sub routine ကို ၿပန္ေခၚမွာပါ။ (Looping ၿဖစ္သြားတဲ့သေဘာပါ။)
ၿပီးရင္ Line နံပါတ္ ၃၅ မွာၿပထားတဲ့အတိုင္း Please Enter the valid input ဆိုၿပီး print ထုတ္ေပးမွာပါ။
Line နံပါတ္ ၃၈ ကေန ၄၁ အထိကေတာ့ process_scp ဆိုတဲ့ sub routine ၿဖစ္ပါတယ္။
Line နံပါတ္ ၃၉ ကေတာ့ shell command ၿဖစ္ၿပီး scp location-of-source-file destination-folder ဆိုတဲ့ command context ကို သက္ဆိုင္ရာ variables value ေတြနဲ ့အစားထိုးၿပီး execute လုပ္မွာပါ။
Line နံပါတ္ ၄၂ ကေန ၅၆ အထိကေတာ့ extract_file ဆိုတဲ့ sub routine ၿဖစ္ပါတယ္။
Line နံပါတ္ ၄၃ ကေတာ့ menu မွာတုန္းက key-in လုပ္ခဲ့တဲ့ $number ဆိုတဲ့ variable ကိုၿပန္ေခၚထားတာၿဖစ္ပါတယ္။
Line နံပါတ္ ၄၄ ကေတာ့ အကယ္၍ $number ရဲ ့value ဟာ 1 ၿဖစ္ခဲ့ရင္ Line နံပါတ္ ၄၅ ကေန ၅၀ အထိကို execute လုပ္သြားမွာပါ။
Line နံပါတ္ ၄၅ ကေတာ့ Deploying Web Application ဆိုတဲ့စာသားကို print ထုတ္ေပးမွာၿဖစ္ပါတယ္။
Line နံပါတ္ ၄၆ ကေတာ့  $appdir ဆိုတဲ့ Web Application's deployed folder နဲ ့ ေအာက္မွာရိွတဲ့ contents ေတြကို ဖ်က္ေပးမွာၿဖစ္ပါတယ္။
Line နံပါတ္ ၄၇ ကေတာ့ $appdir ကိုၿပန္ create လုပ္မွာၿဖစ္ပါတယ္။
Line နံပါတ္ ၄၈ ကေတာ့ ခုနက scp နဲ ့ကူးထားခဲ့တဲ့ application.war file ကို $appdir ထဲကို extract လုပ္ေပးမွာၿဖစ္ပါတယ္။
Line နံပါတ္ ၄၉ ကေတာ့ Web Application Deployed ဆိုတဲ့စာသား ကို print လုပ္မွာၿဖစ္ပါတယ္။
Line နံပါတ္ ၅၀ ကေတာ့ menu ဆိုတဲ့ subroutine ကိုၿပန္ေခၚသံုးထားတာပါ။
Line နံပါတ္ ၅၁ ကေတာ့ အကယ္၍ ရဲ ့value က 1 မဟုတ္ခဲ့ရင္ Line နံပါတ္ ၅၂ ကေန Invalid input ဆိုၿပီး print ထုတ္မွာၿဖစ္ၿပီး
Line နံပါတ္ ၅၃ ကေန sub routine menu ကိုၿပန္ေခၚေပးမွာၿဖစ္ပါတယ္။
Line နံပါတ္ ၅၇ ကေန ၆၀ ကေတာ့ do_exit ဆိုတဲ့ sub routine ၿဖစ္ၿပီး Line နံပါတ္ ၅၈ ကေန Exiting ဆိုၿပီး print ထုတ္မွာၿဖစ္ပါတယ္။ ၿပီးရင္ Line နံပါတ္ ၅၉ က return command နဲ ့program ကို quit လုပ္ေပးမွာပါ။

Wednesday, 12 December 2012

Shell Scripts မ်ား

Shell Scripts ေတြအေၾကာင္း ရွင္းရရင္ေတာ့ တပံုၾကီးပါ။ ကိုယ္တိုင္စာအုပ္ဖတ္ၾကည့္မွ ပဲေတာ္ေတာ္ မ်ားမ်ား အေၾကာင္းကို တီးမိေခါက္မိ ရိွနိုင္ပါ့မယ္။ အခုဒီမွာနမူနာၿပထားတာကေတာ့ Java Process တခုရဲ ့Performance ကို jstat , jmap , နဲ ့ jstack ဆိုတဲ့ Java command ၃ခုကို သံုးၿပီး Monitor လုပ္ရာမွ ရလာတဲ့ result ကို mail နဲ ့ၿပန္ ပို ့ေပးမွာပါ။ Java process ေတြရဲ ့PID ကို သိေအာင္လုပ္တဲ့ေနရာမွာ unix command (ဥပမာ ps -ef လိုမ်ိဳး) ကိုအသံုးမၿပဳဘဲ jps ဆိုတဲ့ Java command ကိုသံုးထားပါတယ္။


ဒီေနရာမွာ အဓိကေၿပာခ်င္တာက script ရဲ ့အလုပ္လုပ္ ပံုသာၿဖစ္ၿပီး Java အေၾကာင္း မဟုတ္ပါ။
က်ေနာ္ကိုယ္တိုင္လည္း Java ကြ်မ္းက်င္သူတေယာက္မဟုတ္ပါ။ ဒီ နမူနာေပးထားတဲ့ script ကေတာ့ က်ေနာ္ ကိုယ္တိုင္ေရးထားတာ ၿဖစ္လို ့ဘယ္သူမဆို အသံုးတည့္မည္ဆိုရင္ လိုအပ္သလို ၿပန္ၿပင္ၿပီးသံုးနိုင္ပါတယ္။

script နွစ္ခုကို ေရးထားၿပီး တခုကေန တခုကိုေခၚသံုးတဲ့ပံုစံပါ။ တစ္ကယ္ေတာ့ JVM တခုထဲကို လုပ္မယ္ဆိုရင္ ဒီတခုထဲနဲ ့တင္ရပါတယ္။ JVM ၂ ခု ဒါမွမဟုတ္ ၂ ခုထက္ပိုခဲ့မယ္ဆိုရင္ အခုၿပထားတဲ့ example ထဲကလိုသံုးမွ အဆင္ေၿပနိူင္မွာပါ။ အခုၿပထားတဲ့ ဥပမာမွာ jvmlog.sh နဲ ့vm.sh တို ့ကို folder တခုေအာက္မွာထားၿပီး jvmlog.sh ကို execute လုပ္လိုက္တာနဲ ့vm.sh ကို ေခၚသံုးသြားမွာပါ။

ေအာက္က script ကို jvmlog.sh ဆိုၿပီး နာမည္ေပးထားပါတယ္။

 #!/bin/sh  
 JDK_32=/usr/jdk/instances/jdk1.6.0/bin  
 echo "Logging JVM for Jgroup ..."  
 /opt/jvmlog/vm.sh `${JDK_32}/jps | grep -v Jps | awk {'if($2=="GossipRouter") print $1, $2 '}`  


#!/bin/sh ဆိုတာ shell နဲ ့run မည့္ဖိုင္ဆိုၿပီး ညြန္းထားတာၿဖစ္ပါတယ္။

JDK_32=/usr/jdk/instances/jdk1.6.0/bin ဆိုတာ JDK Path ကို ေၾကၿငာထားတဲ့ variable ၿဖစ္ပါတယ္။

echo ဆိုတာကေတာ့ shell ရဲ ့print ထုတ္တဲ့ command ၿဖစ္ၿပီး ေနာက္က " " ထဲမွာရိွတဲ့စာသားကို print ထုတ္ေပးမွာၿဖစ္ပါတယ္။

/opt/jvmlog/vm.sh ဆိုတဲ့ script ကိုသြား run ေပးမွာပါ။ ေနာက္က `` ထဲက value က output ၂ခု ထုတ္ေပးမွာၿဖစ္ၿပီး အဲဒီ output ကို vm.sh ဆိုတဲ့ script ထဲမွာ အသံုးၿပဳမွာပါ။

${JDK_32}/jps commandကို run လိုက္ရင္ ရိွသမွ် Java process ေတြရဲ ့PID နဲ ့class name ေတြ ထြက္လာမွာပါ။

grep -v Jps ဆိုတာက အခု run လိုက္တဲ့ jps ရဲ ့process ကို output ထဲကေန remove လုပ္လိုက္တာပါ။

awk {'if($2=="GossipRouter") print $1, $2 '} ကေတာ့ GossipRouter ဆိုတဲ့ Class name ရိွတဲ့ process ရဲ ့PID နဲ ့class name ကို output ၂ ခုအေနနဲ ့ထုတ္တာပါ။ ဒီေနရာမွာ awk ကိုမသံုးဘဲ တၿခား shell command  ေတြ (ဥပမာ cut , sed လိုမ်ိဳး) ေတြကိုသံုးလည္းရပါတယ္။



ေအာက္က script ကို vm.sh ဆိုၿပီး နာမည္ေပးထားပါတယ္။  

 #!/bin/sh  
 SERVER=10.65.0.84  
 JDK_32="/usr/jdk/instances/jdk1.6.0/bin"  
 ROOTDIR="/opt/jvmlog"  
 DATE=`date "+%Y-%m-%d-%H:%M"`  
 RECP="myname@mydomain.com"  
 SNDR="myname@mydomain.com"  
 mkdir -p $ROOTDIR/logs/$2  
 LOGDIR=$ROOTDIR/logs/$2  
 JMAPEND=$LOGDIR/"jmap_"$DATE".log"  
 JSTACKEND=$LOGDIR/"jstack_"$DATE".log"  
 JSTATEND=$LOGDIR/"jstate_"$DATE".log"  
 WORKFILE=/tmp/fxspacelog.txt  
 ${JDK_32}/jmap -histo:live $1 > $JMAPEND  
 echo "Jmap Log for $2 $DATE on ${SERVER}" > ${WORKFILE}  
 echo >> ${WORKFILE}  
 cat $JMAPEND >> ${WORKFILE}  
 sleep 2  
 ${JDK_32}/jstack -l $1 > $JSTACKEND  
 echo >> ${WORKFILE}  
 echo "Jstack Log for $2 $DATE on ${SERVER}" >> ${WORKFILE}  
 echo >> ${WORKFILE}  
 cat $JSTACKEND >> ${WORKFILE}  
 sleep 2  
 ${JDK_32}/jstat -gcutil -t -h20 $1 1000 20 >> $JSTATEND  
 echo >> ${WORKFILE}  
 echo "Jstat Log for $2 $DATE on ${SERVER}" >> ${WORKFILE}  
 echo >> ${WORKFILE}  
 cat $JSTATEND >> ${WORKFILE}  
 mailx -r ${SNDR} -s "Java Log for $2 $DATE on ${SERVER}" ${RECP} < ${WORKFILE}  


#!/bin/sh ဆိုတာ shell နဲ ့run မည့္ဖိုင္ဆိုၿပီး ညြန္းထားတာၿဖစ္ပါတယ္။
SERVER ကေနၿပီး WORKFILE ဆိုတဲ့အထိက variables မ်ားေၾကၿငာထားတာၿဖစ္ပါတယ္။ 
ဒီ script ကို run ရင္ေနာက္ကေန input နွစ္ခုထည့္ေပးရမွာၿဖစ္ပါတယ္။ ပထမ input ($1) ကေတာ့ JVM ရဲ ့PID ၿဖစ္ၿပီး။ ဒုတိယ input ($2) ကေတာ့ သူ ့ရဲ ့class name ၿဖစ္ပါတယ္။

${JDK_32}/jmap -histo:live $1 > $JMAPEND
${JDK_32}/jmap ဆိုတာက jmap command ကိုေခၚတာၿဖစ္ၿပီး၊ -histo:live ဆိုတာကသူ ့ရဲ ့switch ပါ။ $1 ကေတာ့ PID number ၿဖစ္ၿပီး၊ > sign ကေတာ့ output ကို $JMAPEND ဆိုတဲ့ဖို္င္ထဲကို redirect လုပ္သြားဖို ့ပါ။

echo "Jmap Log for $2 $DATE on ${SERVER}" > ${WORKFILE}
သက္ဆိုင္ရာ variable ေတြရဲ ့value နဲ ့ စာေၾကာင္း ကို ${WORKFILE} ထဲကို write ပါလိမ့္မယ္။

echo >> ${WORKFILE}
blank လိုင္း တခုကို print ထုတ္ၿပီး ${WORKFILE} ထဲကို append လုပ္လိုက္တာပါ။

cat $JMAPEND >> ${WORKFILE}
$JMAPEND ထဲက log ေတြကို ${WORKFILE} ထဲကို append လုပ္လိုက္တာပါ။

sleep 2
၂ စကၠန္ ့ေလာက္ ခဏနားေနတာပါ။

ၿပီးရင္ jstat နဲ ့jmap လည္းသူတို ့သက္ဆိုင္ရာ command ေတြ switch ေတြသံုးၿပီး အလုပ္လုပ္ပါလိမ့္မယ္။ အားလံုးၿပီးသြားရင္ရိွသမွ် log ေတြက ${WORKFILE} ထဲမွာ ေရးထားၿပီးသားၿဖစ္ေနပါလိမ့္မယ္။

mailx ကေတာ့ e-mail ပို ့တဲ့ shell command ၿဖစ္ပါတယ္။ သက္ဆိုင္ရာ variable ေတြရဲ ့value ေတြကိုသံုးၿပီး ပို ့သြားမွာၿဖစ္ပါတယ္။ Message Body အေနနဲ ့ ${WORKFILE} ကိုအသံုးၿပဳမွာၿဖစ္ပါတယ္။