Python/Do something

python - ping test 후 결과를 txt 파일로 저장하고, mysql DB에 저장하기 (ping3, pymysql)

pymin 2022. 5. 15. 21:44
반응형

이전에 ping test 결과를 txt 파일로 저장하는 것을 진행했었고, txt 파일을 mysql에 INSERT 하는 것을 진행했었따. 그럼 한개의 파이썬 파일로 ping test 결과를 txt 파일로 저장도 하고, mysql에 INSERT 하려면 어떻게 해야 할까?

1. test 하고자 하는 IP들이 저장된 txt 파일(system_list.txt)을 준비

2. system_list.txt 파일에 있는 IP list에 따라 ping test 결과를 확인하고 ping_result.txt 파일로 저장

3. 저장된 ping_result.txt 파일을 mysql DB에 저장

사실, 해당 작업을 진행하면서 많은 시행착오가 있었는데 해당 내용도 최대한 기록해보고자 한다.

내용이 이해가 가지 않는다면 이전 글을 참고해도 좋고, 댓글을 달면 최대한 설명 드리고자 한다.

우선 첫번쨰로 시도했던 코드는 아래와 같다.

###TEST6
import re
import time
import sys
import pymysql
import shutil

from datetime import datetime
from ping3 import ping,verbose_ping
​
print("ping checking...")
while True:
    with open('C:/pymin/pingtest/system_list.txt', 'r') as f:
        for line in f.readlines():
            site = line.split(',')
            sys.stdout = open('C:/pymin/pingtest/ping_raw.txt','a')
            if site[0][0] == '#':
                print(str(datetime.now())[:19] + ',' + site[1] + ',' + site[0][1:16] + ',' + '-2')
            elif site[0][0] == '=':
                # pass
                sys.stdout = open('C:/pymin/pingtest/ping_raw.txt','w')
            elif site[0][0] == '<':
                pass  
            else:
                result = ping(site[0], timeout=0.5)
                if result == None:
                    print(str(datetime.now())[:19] + ',' + site[1] + ',' + site[0] + ',' + '-1')
                else:
                    print(str(datetime.now())[:19] + ',' + site[1] + ',' + site[0] + ',' + '0')
        f.close()
        shutil.copy('C:/pymin/pingtest/ping_raw.txt', 'C:/pymin/pingtest/ping_result.txt')
        
        conn = pymysql.connect(host='localhost', user='root', password='root', db='bomis', charset='utf8')
        cursor = conn.cursor()
        dsql = "delete from bomis.system_status"
        cursor.execute(dsql)
        conn.commit() 
        conn.close()
​
        f = open('C:/pymin/pingtest/ping_result.txt', 'r')
        while True:
            line = f.readline()
            if not line:
                break
            try:
                final_data = re.split("[,]", line)
                # print(final_data)
                conn = pymysql.connect(host='localhost', user='root', password='root', db='bomis', charset='utf8')
                cursor = conn.cursor()
                sql = "INSERT INTO system_status (alarm_time, system_name, system_ip, rtt_val) VALUES (%s, %s, %s, %s)"
                cursor.execute(sql,final_data)
                conn.commit() 
                conn.close()
            except:
                pass
        f.close()
        time.sleep(10)
    f.close()

하나하나 간단히 설명하자면,

우선 특정 주기로 ping test를 한 후 결과를 저장하고, mysql db에 업데이트 하기 위해 while을 넣고, 마지막에 time.sleep()을 주어서 한 주기가 끝나면 잠시 뒤에 다시 test를 수행하도록 했다.

 

while True:
 f.close()
 time.sleep(10)

다음은 system_list.txt라는 파일을 열고 한줄 한줄 불러들이는데 syetem_list.txt는 ','로 장비, IP 등을 구분해두었기 때문에 site = line.split(',')로 구분을 해준다.

다음으로 ping_raw.txt라는 파일을 만들어서 결과값을 해당 파일에 저장하려고 한다.

다음은 site[0][0]을 통해 라인의 제일 처음에 오는 문자에 따라 어떤 명령을 수행할지를 구분하였다.

(아래 system_list.txt참조)

'#'의 경우 ping test를 잠시 중단하기 위해 ping 결과값 (0:정상, -1:비정상) 을 정상, 비정상도 아닌 -2:test하지 않음으로 설정

'='의 경우 나중에 추가한건데, while문을 계속 돌리면서 ping test 결과값을 저장하기 때문에 이전 ping test 결과값을 지워주는 역할이 필요하다. 따라서 system_list.txt의 제일 처음 라인에 '='을 두어 이전 결과값을 지우고 시작

'<'의 경우 장비를 구분하기 위해서 사용하였다 '<'가 있을 경우는 pass로 무시

system_list.txt의 라인에 위의 문자가 없을 경우 ping test를 시작하도록 한다.

 

ping test 결과가 실패한 경우 '-1'로 표기하고, ping test 결과가 정상적으로 성공한 경우는 '0'을 출력

추가로 아래 ping 명령을 보면 timeout=0.5로 되어 있는데 해당 값은 ping 수행후 몇초간 기다릴건지를 나타내는 옵션이다.

system_list.txt의 라인을 보고 순차적으로 ping test를 수행하기 때문에 timeout값이 높을 경우 많은 IP에 대해서 ping test를 수행하고(+ping 응답이 없는경우) 시간이 너무 오래걸릴 수 있다.

*이는 나중에 병렬로 ping test 를 수행하는 것도 만들어 봐야겠다..

 

이렇게 하면 system_list.txt에 있는 장비,IP를 확인하고 ping test 결과를 ping_raw.txt 파일로 저장한다.

with open('C:/pymin/pingtest/system_list.txt', 'r') as f:
    for line in f.readlines():
        site = line.split(',')
        sys.stdout = open('C:/pymin/pingtest/ping_raw.txt','a')
        if site[0][0] == '#':
            print(str(datetime.now())[:19] + ',' + site[1] + ',' + site[0][1:16] + ',' + '-2')
        elif site[0][0] == '=':
            # pass
            sys.stdout = open('C:/pymin/pingtest/ping_raw.txt','w')
        elif site[0][0] == '<':
            pass  
        else:
            result = ping(site[0], timeout=0.5)
            if result == None:
                print(str(datetime.now())[:19] + ',' + site[1] + ',' + site[0] + ',' + '-1')
            else:
                print(str(datetime.now())[:19] + ',' + site[1] + ',' + site[0] + ',' + '0')
    f.close()

*아래는 system_list.txt 파일의 예시

== PING SYSTEM ver1.0 ==
< EPC >
172.23.19.1,server2,PGW
172.23.19.1,server3,SGW
172.23.193.213,server4,MME
< IMS >
172.23.193.213,server5,MSS
172.23.193.213,server6,TAS
<END>

ping_raw.txt 파일로 저장해도 상관은 없다. 다만 하나하나 직렬로 ping test를 수행하기 때문에 장비가 많을 경우 시간이 걸리게 되고, mysql DB에 한번에 data를 넣기가 복잡해질 수 있고, 타이밍이 안좋으면 data가 빠질수도 있다. 이에 따라 ping_raw.txt 파일이 완성되면 ping_result.txt 파일을 하나 만들어서 해당 파일을 mysql DB에 넣도록 한다.

shutil.copy('C:/pymin/pingtest/ping_raw.txt', 'C:/pymin/pingtest/ping_result.txt')

 

다음은 저장된 ping_result.txt 을 mysql DB로 넣는 과정이다. 이는 지난번에 올려둔 내용과 동일하다.

 

f = open('C:/pymin/pingtest/ping_result.txt', 'r')
while True:
    line = f.readline()
    if not line:
        break
    try:
        final_data = re.split("[,]", line)
        # print(final_data)
        conn = pymysql.connect(host='localhost', user='root', password='root', db='bomis', charset='utf8')
        cursor = conn.cursor()
        sql = "INSERT INTO system_status (alarm_time, system_name, system_ip, rtt_val) VALUES (%s, %s, %s, %s)"
        cursor.execute(sql,final_data)
        conn.commit() 
        conn.close()
    except:
        pass
f.close()
time.sleep(10)

 

이렇게 하면 내가 설정한 주기별로 내가 원하는 여러 장비들에 대해 ping test를 수행하고 해당 결과를 바로바로 mysql DB에 저장할 수 있다.

하지만, 언제나 그렇듯 몇 가지 문제점과 추가 요구사항이 생겼다. 어떤 내용들일까?

우선 추가 요구사항은 ping test 결과를 mysql DB에 계속 쌓지 말고, 이전 data는 지워주세요다. 어떻게 하면 될까? 그냥 한번 지우고 다시 넣으면 된다.

지우는 명령어는 delete 를 사용해도 되고 truncate을 사용해도 된다. (선택해서 지우느냐 그냥 확 날리느냐 정도의 느낌?)

 

conn = pymysql.connect(host='localhost', user='root', password='root', db='bomis', charset='utf8', local_infile=1)
cursor = conn.cursor()
dsql = "truncate bomis.system_status"
sql = "INSERT INTO system_status (alarm_time, system_name, system_ip, rtt_val) VALUES (%s, %s, %s, %s)"
cursor.execute(dsql)
cursor.execute(sql)
conn.commit() 
conn.close()

 

이렇게 해서 mysql DB table의 기존 data는 지우고 새로운 data만 추가하도록 했는데.. 많은 양의 장비, IP를 test하다가 보니 타이밍에 따라 모든 장비에 대한 결과가 mysql DB에 있지 않고 잠깐이지만 시간이 지나야 모든 data가 저장이 된다.. 상관이 없을 수도 있지만 그래도 어떻게 하면 한번에 DB에 저장할 수 있을까?

INSERT로 한줄 한줄 넣지말고 LOAD DATA를 이용해서 파일채로 넣어버리자. 이렇게 변경하면 끝!

conn = pymysql.connect(host='localhost', user='root', password='root', db='bomis', charset='utf8', local_infile=1)
cursor = conn.cursor()
dsql = "truncate bomis.system_status"
sql = 'LOAD DATA LOCAL INFILE "C:/pymin/pingtest/ping_result.txt" INTO TABLE bomis.system_status CHARACTER SET utf8 FIELDS TERMINATED BY "," LINES TERMINATED BY "\n" (alarm_time, system_name, system_ip, rtt_val)'
cursor.execute(dsql)
cursor.execute(sql)
conn.commit() 
conn.close()

 

최종 코드는 첨부하지 않았지만 위의 내용을 읽어보면 쉽게 나만의 스크립트를 완성할 수 있을 거라고 생각한다. 혹시 궁금한 사항이 있으면 댓글 달아주세요.

다음에는 ping test를 병렬로 수행하는 것을 고민해볼까..

반응형