일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- 연산자
- patch
- PERL
- fdisk
- rac
- SQL
- oracle
- php5
- mariaDB
- Linux
- command & perl
- cygwin
- RHEL4
- Unix
- sqlplus
- bash
- solaris
- oracle install
- MySQL
- perl + 정규표현식
- prompt
- dba
- perl string
- Network
- 오라클
- perl one-liner
- grid
- solaris network
- memory
- Oracle RAC
Archives
- Today
- Total
DATA 전문가로 가는 길
[Perl] Expect를 이용한 서버 체크하는 방법 (cygwin용) 본문
오늘은 제가 회사에서 사용하고 있는 모듈 하나를 설명 해드리겠습니다.
net:telnet라는 좋은 모듈도 있지만 ssh를 이용해서 서버로 접근 한 후 명령어를 치고 나오려면 아무래도 Expect가 더 효율적이라고 생각 됩니다.
http://search.cpan.org/~rgiersig/Expect-1.21/Expect.pod
자세한 세부적인 설명은 해당 사이트에 가시면 Expect의 사용법을 자세하게 알수 있습니다.
Windowns + Cygwin + Perl
제가 구성한 환경입니다. 각 서버에 존이 틀려서 서버서에 서버로 이동 하지 못해 개인 PC에 해당 환경을 구성 하였습니다.
expect는 다른 응용 어프리케이션과 상호대화(interactive) 할 수 있게 만든 모듈입니다.
사용 벙법은 그렇게 어렵지 않고 간단하게 프로그램을 구현 할 수 있습니다.
ecpect를 이용하면 다른 어플리케이션과 상호 대화를 할 수 있게 됨으로써 자동화된 프로그램을 만들수가 있으며, telnet를 예를 들면, expect를 이용해서 telnet와 상호작용하게 함으로써 자동로그인 하는 프로그램을 만들 수 있습니다.
간단한 예로 telnet 을 써서 어떤 호스트에 연결하면 로그인 하기 위해서 수동 "아이디"와 "패스워드"를 입력 해야 할 것입니다.
telnet 203.234.151.xxx 명령어를 실행하면 "login :"과 "password :"와 같은 표준 출력을 만나게 되고 해당 아이디와 패스워드를 입력해야만 접근이 가능 합니다.
이러한 수동으로 되는 작업을 자동화 시킬 수 있는게 expect라고 생각 하시면 됩니다.
우선 필요한 모듈을 설치 하셔야 겠죠?
소스 설치 :
터미널을 통해서 상호대화 하는 프로그램임으로 터미널 관련 모듈 :. IO-Tty-1.08.tar.gz
expectperl expect 모듈은 확장 모듈 : Expect-1.21.tar.gz
cpan 설치 :
install IO::Tty;
install Expect;
그럼 이중에서 expect를 이용한 원격 자동 시스템 체크하는 방법을 구현 해보도록 하겠습니다.
아이피 | 아이디 | 패스워드 |
203.221.xxx.111 | estenpark | passwd1 |
203.221.xxx.112 | mass | passwd2 |
203.221.xxx.113 | root | passwd3 |
문제는 아이피도 다르고 아이디/패스워드 모두 다릅니다.
그럼 처음부터 2차원 배열을 이용해서 각 원소를 넣는 방법도 있고 아니면 구조체를 이용해서 사용 하는 방법도 있을 겁니다.
그중 가장 완성도가 높은 자료구조를 이용한 서버 접근을 하도록 하겠습니다.
#!/usr/bin/perl use strict; use warnings; use Expect; my %server_data = ( '203.221.xxx.111' => {id=>'estenpark', pass=>'passwd1' }, '203.221.xxx.112' => {id=>'mass', pass=>'passwd2' }, '203.221.xxx.113' => {id=>'root', pass=>'passwd3' }, ); foreach my $ip ( sort keys %server_data ) { printf "IP : %16s ID : %10s PW : %16s \n", $ip, $server_data{$ip}->{id}, $server_data{$ip}->{pass}; my $conn = "ssh -l ".$server_data{$ip}->{id}." ".$ip; my $passwd = $server_data{$ip}->{pass}; my $file_name = "log/".$server_data{$ip}->{id}."_".$ip; my $timeout = 100; my $exp = Expect->spawn("$conn"); $exp->log_file("$file_name","w"); $exp->expect($timeout, [qr ': $' => \&inputpassword], [qr '[#>\$] $' => \&gethttpnum], [timeout => \&timeouterr],); sub timeouterr { die "Login Time Out\n"; } sub inputpassword { my $lexp = shift; $lexp->send("$passwd\n"); exp_continue; } sub gethttpnum { my $lexp = shift; $lexp->send("checklist.sh\n"); $lexp->send("exit\n"); $exp->log_file(); exp_continue; } } |
각 서버에 접근 하여 checklist.sh를 실행하고 빠져 나오는 프로그램 입니다.
my %server_data = ( '203.221.xxx.111' => {id=>'estenpark', pass=>'passwd1' }, '203.221.xxx.112' => {id=>'mass', pass=>'passwd2' }, '203.221.xxx.113' => {id=>'root', pass=>'passwd3' }, ); |
각 서버의 아이피 별로 {id},{pass} 해시 키를 만들고 원하는 값을 출력 하면 됩니다.
foreach my $ip ( sort keys %server_data ) { .. .. |
%server_data 루프는 총 3번 돌게 됩니다.
my $exp = Expect->spawn("$conn"); |
$exp->log_file("$file_name","w"); |
실제로 expect() 함수가 돌기 전에 파일을 생성 합니다. (단일 서버로 접근 할려면 소스의 하단에 내려도 됩니다.)
$exp->expect($timeout, [qr ': $' => \&inputpassword], [qr '[#>\$] $' => \&gethttpnum], [timeout => \&timeouterr],); |
특히 패스워드 부분은 ': $' 한 이유는 서버별로 "passwd : ", "암호 : " 터미널에 출력되는 문자열이 다르기 때문에 ": "을 취급하는 문자열이 발견 되면 해당 함수에서 값을 가지고 오게 됩니다.
\&inputpassword 함수를 불러오는 방법을 흔히 $inputpassword()로 생각 하시겠지만 저 문법은 함수에 대한 래퍼런스 입니다.
timeout 이부분은 실제로 ssh 서버의 이상으로 인하여 장기간 동안 원하는 문자열을 만나지 못할 경우 프로그램에서 block된 상태에서 머무를수도 있기 때문에 일정 시간 후에 행동을 결정 하는 부분입니다.
sub inputpassword { my $lexp = shift; $lexp->send("$passwd\n"); exp_continue; } |
sub gethttpnum { my $lexp = shift; $lexp->send("checklist.sh\n"); $lexp->send("exit\n"); $exp->log_file(); exp_continue; } |
예를 들자면
checklist.sh
set CHK=`grep Average system |awk '{print $5}'` if ( $CHK <= 50 ) then |
각 시스템에 필요한 정보를 checklist.sh 안에 설정 하고 수행 하면 각 서버별로 정상/비정상 유무를 확인 할 수 있을 거라고 생각 합니다.
이상이 없을 경우 : printf "system01|STEP01_01|Y\n"
이상이 있을 경우 : printf "system01|STEP01_01|N|%d\n" $CHK
서버에서 시스템을 체크 하기 위해서는 정말 쉬운 일은 아닙니다. 지금은 서버 3대를 비유하여 프로그램을 작성 하였지만 호스팅 업체나 기타 서버가 많은 회사들은 100대 이상 넘을 거라고 생각 합니다.
그럼 그 100대에 들어가서 체크하는 것도 한계가 있는 거겠죠.
perl을 시작하면서 가장 인상 깊었던 말이 "게을러 져라" 라고 하는 문구 입니다.
비록 말 자체는 좋은 표현이 아닐지 모르겠지만 어떤 업무를 하다보면 조금더 능동적으로 바꾸고 싶거나 시간을 최대한 아낄 수 있는 방법이 아닌가 생각 됩니다.
그럼 이상...Expect 모듈 사용기..
참고 자료
================================================================================
사이트 이름
================================================================================
http://aero.springnote.com/ (aero님)
http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/JPerl/expect (윤상배님)
http://search.cpan.org/~rgiersig/Expect-1.21/Expect.pod (cpan : expect)
http://cafe.naver.com/perlstudy.cafe (대한민국Perl커뮤니티)
================================================================================
'Programming > Perl' 카테고리의 다른 글
[Perl] Perl Command-Line Options (2) | 2009.04.09 |
---|---|
[Perl] 서브루틴 (0) | 2009.04.07 |
[Perl] Hash(해쉬)란? (2) | 2009.03.27 |
[Perl] 원라이너 디렉토리 안에 문자열을 찾아 각 월별 건수 확인 (4) | 2009.03.26 |
[Perl] Dereference 란? (2) | 2009.03.26 |
Comments