[scrap] 텔레그램(Telegram)으로 서버 모니터링하기

http://truefeel.tistory.com/224

 

메신저 검열로 ‘텔레그램(Telegram)’ 광풍이 불고 있다. 개인적으로 카톡을 자주 사용하지 않아, 텔레그램이 절실(?)하게 필요하지 않다. 하지만 텔레그램을 사용해야할 이유가 생겼다. 텔레그램이 서버에서 사용할 수 있는 CLI를 제공하고 있고, lua나 python으로 손쉽게 메신저와 연동할 수 있다.

그래서 텔레그램용 lua스크립트를 만들어서 서버 상태를 폰에서 받아볼 수 있다. 예를 들어 특정 서버의 MRTG/RRD를 메신저로 요청하면 그 이미지를 받아 볼 수 있다. 서버의 load값도 같은 방식으로 return받을 수 있다. 서버장애 문자를 텔레그램으로 받을 수 있도록 하신분도 있다. (※ 개인적으로는 이미 SMS로 받고 있는 것을 다시 텔레그램용으로 만들 필요는 없었다.)

텔레그램 CLI설치는 ‘리눅스에 텔레그램(Telegram) CLI 설치‘ (글 좋은진호)를 참고하고, 이 글은 서버 모니터링용 텔레그램 스크립트와 실제 사용 예를 보여줄 것이다.

1. 텔레그램 lua 스크립트 기본 구조

메시지를 수신하면 on_msg_receive 함수가 호출된다. 이 함수내에서 send_msg, send_photo, send_text 등의 함수를 이용해서 메시지를 상대에서 보낼 수 있다. 다음은 ‘hello’를 수신하면, 결과를 보내준다.

[ 스크립트 기본 구조 : hello.lua ]

function on_msg_receive (msg)

if ( msg.text == ‘hello’ ) then

send_msg(msg.from.print_name, “world”, ok_cb, false)

return

end

end

function ok_cb(extra, success, result)

end

$ bin/telegram-cli -s hello.lua

… 생략 …

[14:21]  Jinho >>> aa

User Jinho is typing

[14:22]  Jinho >>> bb

User Jinho is typing

User Jinho is typing

[14:22]  Jinho >>> 헬로우

User Jinho is typing

[14:22]  Jinho >>> hello

[14:22]  Jinho <<< world

User Jinho marked read 1 outbox and 0 inbox messages

>

telegram-cli 실행화면[ telegram-cli 실행화면 ]

스마트폰 어플 화면[ 스마트폰 어플 화면 ]

 

2. 서버모니터링용 스크립트 살펴보기

[ 모니터링용 스크립트 일부 : server_mon.lua ]

now = os.time()

dir_cmd = “/home/cnx/cmd”

cmd_ping = “cd “.. dir_cmd ..”; sh ping.sh”

cmd_load = “cd “.. dir_cmd ..”; sh load.sh”

cmd_netlog = “cd “.. dir_cmd ..”; sh show_netlog.sh”

cmd_mrtg = “cd “.. dir_cmd ..”; perl mrtg.pl”

cmd_404 = “cd “.. dir_cmd ..”; perl 404.pl”

mrtg_res = {“load”, “swap”, “public_if”, “private_if”, “disk_io”, “memory_free”, “memory_inactive”}

auth_phone = {[“821012345678”] = true, [“821087654321”] = true }

— 메시지 수신 처리

function on_msg_receive (msg)

if msg.date < now then

return

end

if msg.out then

return

end

— command

local recv_msg = “”

if ( msg.text ~= nil ) then

recv_msg  = string.gsub(msg.text,”[;|<>]”,””)– 받은 msg중에 ;, |, <, > 등의 문자는 지움

end

local cmd, arg  = split(recv_msg)– exam : ping a b c d => cmd = “ping”, arg = “a b c d”

local file_name = “”

cmd = string.lower(cmd)

print(“receive : “, cmd, “n”)

— user_info

print(“Name    : “, msg.from.print_name)– 메시지 보낸사람 real name (Jinho)

print(“Phone   : “, msg.from.phone)– 메시지 보낸사람 전화번호  (8210AAAABBBB)

print(“Msg Num : “, msg.id)– 메시지 번호

print(“to.Name : “, msg.to.print_name)

— 일반대화, 비밀대화 구분해서 메시지 전송

if (msg.to.id == our_id) then

user_id= msg.from.print_name– 일반대화창

else

user_id= msg.to.print_name– 비밀대화창

end

— auth (지정한 폰번호만 인증)

if auth_phone[msg.from.phone] then

print “auth    : OK ”

else

print “auth    : invalid user”

return

end

mark_read(user_id, ok_cb, false)– 읽은 메시지로 표시

— ping

if ( cmd == ‘ping’ ) then

os.execute(cmd_ping .. arg)

send_text(user_id, dir_cmd ..’/result_ping.txt’, ok_cb, false)

return

end

— load

if ( cmd == ‘load’ ) then

… 생략 …

end

— netlog

if ( cmd == ‘netlog’ ) then

… 생략 …

end

— MRTG

if ( cmd == ‘mrtg’ ) then

os.execute(cmd_mrtg .. arg)

arg = trim(arg)

for i=1, table.maxn(mrtg_res) do

file_name = dir_cmd ..”/”.. arg ..”_”.. mrtg_res[i] ..”-day.png”– DIR/FILE

— print (file_name)

if ( file_exists(file_name) ) then

send_photo(user_id, file_name, ok_cb, false)

end

end

return

end

— web 403/404 status

if ( cmd == ‘404’ ) then

… 생략 …

end

— help

— if ( cmd ~= ” ) then

if ( cmd == ‘help’ ) then

send_text(user_id, dir_cmd ..’/help.txt’, ok_cb, false)

end

end

… 생략 …

주요부분을 살펴보자.

if ( cmd == ‘ping’ ) then

os.execute(cmd_ping .. arg)

send_text(user_id, dir_cmd ..’/result_ping.txt’, ok_cb, false)

return

end

모니터링용 스크립트에서는 각 명령어마다 외부 명령을 호출하고 결과를 text파일로 저장했다. 그리고, 그 text파일 내용을 메시지로 뿌려지도록 했다. 명령어 추가는 if ( cmd == ‘명령어 ‘ ) then 형태로 확장해주고, 외부 명령 처리할 스크립트만 만들어주면 된다.

 

if (msg.to.id == our_id) then

user_id= msg.from.print_name– 일반대화창

else

user_id= msg.to.print_name– 비밀대화창

end

secret chat을 지원한다. msg.to.id == our_id 라면, 즉 받는 사람과 CLI 메신저 유저가 같다면 일반대화창으로 대화중이고, 그렇지 않는 것은 비밀대화이다. 비밀대화는 msg.from.print_name이 아닌 msg.to.print_name 에게 메시지를 보내야 한다. 아래 루틴이 없다면 폰에서 비밀대화로 메시지를 보냈더라도 CLI에서는 응답을 일반대화창으로 보낸다.

if auth_phone[msg.from.phone] then

print “auth    : OK ”

else

print “auth    : invalid user”

return

end

auth_phone 에서 지정한 휴대폰에서만 명령을 처리한다.

mark_read(user_id, ok_cb, false)

메시지를 읽은 것으로 표시한다.

※ lua스크립트를 처음해봤다. lua 매뉴얼을 보면서 스크립트를 하루에 만들고, 그 이후에 한번 기능을 추가한 정도다. 그래서 스크립트 lua개발자들이 보기에는 좋지 않은 부분도 있을 것이다. lua고수에게는 연필깍는 칼처럼 뻑뻑하게 보일 수 있겠지만, 누군가 다듬어 사용하면 생선회감용 칼처럼 휼륭(?)하게 쓰일 수 있을 것 같다.

※ ping.sh, load.sh 등의 외부 호출 스크립트는 공개하지 않겠다. 내부 서버들의 데이터를 추출하는 부분이라서 공개하기가 쉽지 않고, 이 글을 읽는 분들의 서버상황이 저와는 다를테니 스크립트 내용보다는 호출 방식만 눈여겨 보면 좋을 것 같다.

3. 텔레그램 CLI 실행

$ bin/telegram-cli -s server_mon.lua

또는

$ bin/telegram-cli -s server_mon.lua -d &

테스트위해서는 -s 옵션만, 추후 운영하기 위해서는 -d 옵션으로 넣어 데몬형태로 실행한다.

telegram-cli 화면[ telegram-cli 화면 : help를 보내주고, ping 결과를 보내준 화면 ]

텔레그램 스마트폰 어플 화면[ 스마트폰 어플 화면 : 아무키나 입력해서 도움말을 확인, 서버그룹별 ping과 개별 IP별 ping 결과 요청 ]

※ 스크립트를 수정해서 ‘help’명령을 내렸을 때만 도움말을 보여주도록 바꿨다. 스크립트 수정 전에 캡쳐한 것임.

telegram-cli 화면[ telegram-cli 화면 : load 결과, MRTG 그래프 7개를 보내준 화면 ]

텔레그램 어플 화면[ 스마트폰 어플 화면 : load 결과, MRTG 그래프를 받은 화면 ]

 

4. 참고자료

* 텔레그램 CLI 소스에 들어있는 test.lua

* 텔레그램 README-LUA

* Lua check if a file exists

* Telegram Messenger Client