목공책 하나 들이셔요~

2014년 5월 30일 금요일

Expect를 이용한 sftp 자동화

프로젝트를 하다 보면 이런 일 많습니다. war파일을 빌드하고 서버에 올리고, 수정 사항 생겨서 또 빌드하고 서버에 올리고... 이런 작업이 계속 반복됩니다. 그나마 서버 하나에 올리는 것이면 참을만 하지만, 동일한 파일을 10개의 서버에 올려야 한다면 끔찍해 집니다.

발명의 어머니는 게으름이라고 했나요? 단순 반복 작업으로 지쳐갈 때면 이걸 자동화할 방법이 없나... 하고 찾아보게 됩니다. 요즘은 대부분 sftp를 사용하는데 sftp의 경우 보안이 강화된 파일 전송 방법이다 보니 서버의 계정과 암호를 자동으로 입력하지 못하게 되어 있습니다. (물론 SSH 키를 사용하는 방법으로 로그인 과정을 회피할 수 있지만, 이건 다음 글에서 소개 드리도록 하겠습니다)



sftp로 파일 전송하는 걸 자동화하는 스크립트를 만들어 보자는 것이 이 글의 내용입니다. 그리고 그 도구는 "expect" 입니다.

Expect란 무엇인가?

expect는 대화형 어플리케이션을 자동화하기 위한 용도로 개발된 프로그램입니다. 예를 들어 프로그램을 실행하면 아이디와 암호를 묻거나 Yes 혹은 No라고 응답해야 하는 경우가 있는데 이런 질문 때문에 쉘 스크립트로 자동화를 못하는 경우가 많습니다.

expect는 이런 상황에서 어떤 텍스트가 출력되길 기다렸다가 (expect) 그 텍스트를 만가게 되면 어떤 행동을 할 수 있게 하는 스크립트 도구입니다. expect의 홈페이지는 http://expect.sourceforge.net/ 입니다. 리눅스의 경우 시냅틱으로 expect를 설치하거나 "sudo apt-get install expect" 명령을 실행하여 쉽게 설치할 수 있습니다.

윈도우즈의 경우 위 홈페이지에서 다운로드 받으면 됩니다. 그런데 Tcl/Tk로 작성된 도구라 윈도우즈에서의 설치가 깔끔하지 않을 수 있습니다.


expect 툴의 명령어는 여러가지가 있지만 가장 중요한 네가지만 알아도 대부분의 코딩을 할 수 있습니다. 각각에 대해 살펴보면 다음과 같습니다.
  • spawn : 특정 프로그램을 실행 시킵니다.
  • expect : 그 프로그램에서 출력되는 문자열 중에서 반응할 패턴을 지정합니다.
  • send : 그 프로그램에 키보드 입력을 하는 것 처럼 출력합니다.
  • interact : expect 툴의 대화 모드를 중지하고 사용자에게 제어를 넘깁니다.
간단한 sftp 접속 스크립트 만들기

지금까지 살펴본 지식으로 간단한 sftp 접속 스크립트를 만들어 보겠습니다. 가장 간단한 예로 로컬호스트에 접속하여 파일 하나를 전송해 봅니다. 이를 코딩하기 위해서는 실제로 어떻게 sftp 프로그램이 반응하고 입력해야 하는지를 먼저 살펴 보아야 합니다. 다음과 같을 것입니다.

sftp myserver
user@myserver's password: PASSWORD\r
Connected to myserver
sftp> put test.xml\r
sftp> quit\r

위 예시에서 붉은색 부분이 사용자가 쳐넣는 부분이고 \r은 ENTER키를 의미합니다. 즉 sftp 명령을 spawn하고 "password:"를 기다려서 암호를 입력하고, "sftp>"를 기다려서 put 명령을 보내면 됩니다. 종합하면 다음과 같이 스크립트를 만들 수 있습니다.

#!/usr/bin/expect -f

spawn sftp myserver
expect "password:" { send "PASSWORD\r" }
expect "sftp>" { send "put test.xml\r" }
expect "sftp>" { send "quit\r" }
interact

위와 같이 작성한 스크립트를 upload.exp라는 파일명으로 저장하고 "expect upload.exp"를 실행하면 자동으로 파일을 업로드함을 볼 수 있습니다. expect 명령 뒤의 패턴 그리고 {} 블럭 내에 수행할 동작을 넣는 것입니다. 마지막에 quit을 보내고 interact 명령을 실행하면 quit에 의해서 자연스럽게 sftp가 종료되게 됩니다. 만일 interact를 넣지 않으면 expect 스크립트가 종료되는 순간 sftp도 같이 강제 종료됩니다.

여러 서버에 파일 보내기

간단한 expect 스크립트를 통해 sftp 자동 업로드를 시험해 보았으면 이제 실제로 여러개의 서버에 파일을 보내는 방법을 알아 봅니다. 이를 위해서 expect 스크립트의 함수 정의 구문을 사용합니다. 다음과 같은 expect 스크립트를 작성합니다.

#!/usr/bin/expect -f

set timeout 600

proc upload { user ipaddr port password } {
    spawn sftp -P $port $user@$ipaddr
    expect -re "yes/no" {
        send "yes\r"
        exp_continue
    } -re "password:" {
        send "$password\r"
    }
    expect "sftp>"
    send "put /some/where/test.war\n"
    send "quit\r\r"
}

puts "\n====== Uploading server1"
upload userid1 11.11.11.11 22 password1

puts "\n====== Uploading server2"
upload userid2 11.11.11.12 22 password2

puts "\n====== Uploading server3"
upload userid3 11.11.11.13 22 password3

스크립트를 자세히 살펴보면 먼저 timeout을 길게 설정합니다. 600은 대략 10분 정도의 타임아웃입니다. 이 타임아웃은 expect 구문이 지정한 패턴을 얼마나 기다리느냐입니다. 이 디폴트 값은 대략 1분 정도인데 만일 파일의 크기가 커서 전송하는데 1분 이상이 걸린다면 expect 패턴 검사에 실패하면서 정상적으로 스크립트가 실행되지 않습니다. 그러므로 전송하는 파일의 크기에 맞추어 타임아웃을 설정해야 합니다.

다음으로 upload라는 함수를 정의합니다. 인자로 userid, ipaddr, port, password를 받습니다. 이 정보들로 sftp의 접속 구문을 실행합니다. 다음 expect 구문이 두개의 패턴을 기다리고 있습니다. 하나는 yes/no를 기다리고 하나는 password를 기다립니다. 이렇게 expect 구문에 두개의 패턴이 있으면 둘 중 하나라도 걸리면 해당 항목의 스크립트를 실행합니다.

sftp로 새로운 서버에 접속하면 아래와 같이 서버측 키를 클라이언트에 저장할 것이냐고 묻습니다. 그래서 yes/no 패턴을 기다려서 yes로 응답해 줍니다. 이렇게 한번 키를 저장하고 나면 다음에는 묻지 않기 때문에 위와 같이 두개의 패턴을 명시하여 OR로 처리하도록 하는 겁니다. yes/no 패턴에 대해서는 "yes"를 send한 후에 exp_continue를 실행하는데 이는 for문에서의 continue와 동일한 의미로 다시 그 expect 구문을 실행함을 의미합니다. 그래서 다음의 "password:" 패턴을 기다리게 되는 것이죠.

The authenticity of host '[myserver.iptime.org]:22 ([11.11.11.33]:22)' can't be established.
ECDSA key fingerprint is 37:ef:d7:29:af:b2:04:56:ef:a0:02:af:8a:1f:79:f0.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[myserver.iptime.org]:22,[11.11.11.33]:22' (ECDSA) to the list of known hosts.
userid@myserver.iptime.org's password: 

나머지는 앞에서 본 것과 동일합니다. 이렇게 함수로 정의 되었으면 필요한 서버 수와 계정 정보에 따라 스크립트 아랫쪽에 upload 함수를 불러주면 됩니다. 이렇게 해서 아무리 많은 서버라도 스크립트 실행 한 번으로 자동으로 파일을 업로드할 수 있습니다.

보안에 관한 주의사항

위와 같이 암호가 평문으로 포함된 스크립트를 작성하는 것은 보안에 문제가 많습니다. 그 스크립트가 누출이라도 된다면 여러대의 서버 계정 정보가 누출되게 됩니다. 그러므로 최소한 해당 스크립트는 작업자의 계정만 읽고 쓸 수 있도록 권한을 조정해야 합니다.

스크립트에 암호를 넣지 않고 클라이언트 인증키를 설치하여 sftp 인증을 자동화할 수도 있는데 이에 대해서는 아래 관련글 "SSH 자동 로그인 하기"를 참조하시기 바랍니다.

어쨌든 expect 툴을 이용하면 sftp뿐 아니라 다양한 대화형 프로그램들에 대해 입력과 실행을 자동화할 수 있습니다.

관련글 :
  - SSH 자동 로그인 하기

댓글 없음:

댓글 쓰기