import os
import sys
sys.path.append(os.getcwd() + "\lib")
import paramiko
from paramiko import SSHException, AuthenticationException
import datetime
import time
import pandas as pd
import threading
import PySimpleGUI as psg
from queue import Queue
# 엑셀 읽어오기
def xlsx_read(pd_name):
pd_xlsx = pd.read_excel(pd_name, engine = "openpyxl", sheet_name=0)
try:
pd_name = pd_xlsx['hostname'].values.tolist()
pd_ip = pd_xlsx['ip'].values.tolist()
dev_len = str(len(pd_ip))
filenumber = 1
log_file_path = "./Log(%d)[%s]"%(filenumber,dev_len) # 폴더 생성 이름 정의
if not os.path.isdir("./Log[%s]"%(dev_len)) and not os.path.isdir(log_file_path): # if로 정의된 폴더가 없으면
log_file_path = "./Log[%s]"%(dev_len)
os.mkdir(log_file_path)
else: # 그 외
while os.path.isdir(log_file_path): # 중복 폴더가 없을 때 까지
log_file_path = "./Log(%d)[%s]"%(filenumber,dev_len)
filenumber += 1
os.mkdir(log_file_path) # 폴더 생성
return pd_ip, pd_name, log_file_path
except:
psg.popup("", " 파일이 잘못되었습니다. \x00", "",title='정보')
# Choice
def Run():
if values['-Only_T-']:
DEVICES, DEVICES_NAME, LOG_FILE_PATH = xlsx_read(values['-File-'])
USER_TAC = values['-TacacsID-']
PASSWD_TAC = values['-TacacsPW-']
USER_LOCAL = ''
PASSWD_LOCAL = ''
PORT = values['-Port-']
COMMAND = values['-CommandLine-']
if values['-Only_L-']:
DEVICES, DEVICES_NAME, LOG_FILE_PATH = xlsx_read(values['-File-'])
USER_TAC = ''
PASSWD_TAC = ''
USER_LOCAL = values['-LocalID-']
PASSWD_LOCAL = values['-LocalPW-']
PORT = values['-Port-']
COMMAND = values['-CommandLine-']
if values['-T_W_L-']:
DEVICES, DEVICES_NAME, LOG_FILE_PATH = xlsx_read(values['-File-'])
USER_TAC = values['-TacacsID-']
PASSWD_TAC = values['-TacacsPW-']
USER_LOCAL = values['-LocalID-']
PASSWD_LOCAL = values['-LocalPW-']
PORT = values['-Port-']
COMMAND = values['-CommandLine-']
return DEVICES, DEVICES_NAME, LOG_FILE_PATH, USER_TAC, PASSWD_TAC, USER_LOCAL, PASSWD_LOCAL, PORT, COMMAND
# 진행중 표시 창
def Processing_Window():
complet = 0
err_que = Queue()
# SSH Connect
def sessions(DEVICE, DEVICE_NAME, USER, PASSWD_SECRET, USER_LOCAL, PASSWD_LOCAL, PORT):
lock = threading.Lock()
nonlocal complet
dtime = 0
login_Cnt = 0
Cmd_Cnt = 0
SSH_Client = paramiko.SSHClient()
SSH_Client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
SSH_Client.connect(DEVICE, username=USER, password=PASSWD_SECRET, port=PORT, allow_agent=False, look_for_keys=False, timeout=300 ,auth_timeout=60, channel_timeout=60)
SHELL = SSH_Client.invoke_shell(width = 999)
CMD = COMMAND.split('\n')
cv = ''
# enable 모드 진입
while True:
dtime += 1
if SHELL.send_ready():
if login_Cnt == 0:
time.sleep(1)
SHELL.send('en\n')
login_Cnt = 1
if login_Cnt == 1:
time.sleep(1)
SHELL.send('%s\n\n\n'%PASSWD_SECRET)
login_Cnt = 2
if login_Cnt == 2:
break
if dtime == 300:
break
# 버퍼 초기화
while not SHELL.recv_ready():
time.sleep(1)
tmp = SHELL.recv(65535).decode(encoding='utf-8')
# user 모드 확인 버퍼
SHELL.send('\n')
while not SHELL.recv_ready():
time.sleep(1)
tmp = SHELL.recv(65535).decode(encoding='utf-8')
# 중간 종료
if dtime == 300 or '>' in tmp:
err_que.put(DEVICE)
SHELL.close()
SSH_Client.close()
else:
SHELL.send('\n')
while True:
if SHELL.send_ready():
SHELL.send('%s\n'%CMD[Cmd_Cnt])
Cmd_Cnt += 1
if Cmd_Cnt == len(CMD):
break
while True:
time.sleep(5)
if SHELL.recv_ready():
cv += SHELL.recv(65535).decode(encoding='utf-8')
else:
break
SHELL.close()
SSH_Client.close()
cv = cv.replace('\r\n','\n')
dev_log = open('%s\%s.log'%(LOG_FILE_PATH, DEVICE_NAME), "w+", encoding='utf-8')
dev_log.write(cv)
dev_log.close()
lock.acquire()
complet = complet + 1
lock.release()
except AuthenticationException:
if Account_Mode:
sessions(DEVICE, DEVICE_NAME, USER_LOCAL, PASSWD_LOCAL, '', '', PORT)
else:
err_que.put(DEVICE)
lock.acquire()
complet = complet + 1
lock.release()
except (SSHException, TimeoutError):
err_que.put(DEVICE)
lock.acquire()
complet = complet + 1
lock.release()
except:
err_que.put(DEVICE)
lock.acquire()
complet = complet + 1
lock.release()
###################################################################################################################################################
# SSH Processing
def SSH_Threading():
dc = 0
thrs = []
while dc < len(DEVICES):
thread_2 = threading.Thread(target=sessions, args=(DEVICES[dc], DEVICES_NAME[dc], USER_TAC, PASSWD_TAC, USER_LOCAL, PASSWD_LOCAL, PORT))
thread_2.start()
dc += 1
time.sleep(.5)
thrs.append(thread_2)
for thr in thrs:
thr.join()
###################################################################################################################################################
layout_1 = [
[psg.Frame('',[
[psg.Text('진행중 ',key='-now-',font=('bold',20))]],element_justification='c', vertical_alignment='c', border_width=0)]]
window_1 = psg.Window('', layout_1, grab_anywhere=True, finalize=True, no_titlebar=True, keep_on_top=True)
thread_1 = threading.Thread(target=SSH_Threading)
thread_1.start()
tick = 1
while True:
event, values = window_1.read(timeout=1000) # 1초
# 중지
if event == '-Stop-':
sys.exit()
# 스레드 1번이 살아 있으면 조건문 수행
if thread_1.is_alive():
percent = ((complet/len(DEVICES)) * 100)
if (tick%3) == 1:
window_1['-now-'].update('진행중. \n{}% 완료'.format(int(percent)))
if (tick%3) == 2:
window_1['-now-'].update('진행중.. \n{}% 완료'.format(int(percent)))
if (tick%3) == 0:
window_1['-now-'].update('진행중... \n{}% 완료'.format(int(percent)))
tick += 1
continue
else:
break
window_1.close()
return err_que
if __name__ == "__main__":
CHECK_TF = True
psg.theme('DarkBlack1')
# GUI 구성 레이아웃
layout = [[psg.Frame(layout=[
[psg.Text('ID',justification='center',size=(10,1),pad=(0,13)),psg.Input(key='-TacacsID-',size=(30,1),pad=(0,13))],
[psg.Text('PW',justification='center',size=(10,1),pad=(0,13)),psg.Input(password_char='*',key='-TacacsPW-',size=(30,1),pad=(0,13))],
[psg.Text('Local ID',justification='center',size=(10,1),pad=(0,13)),psg.Input(key='-LocalID-',size=(30,1),pad=(0,13))],
[psg.Text('Local PW',justification='center',size=(10,1),pad=(0,13)),psg.Input(password_char='*',key='-LocalPW-',size=(30,1),pad=(0,13))],
[psg.Text('Port',justification='center',size=(10,1),pad=(0,10)),psg.Input(key='-Port-',default_text='22',size=(30,1),pad=(0,13))],],
title='계정 정보 입력',element_justification='c',vertical_alignment='t',size=(350,250)),
psg.Frame('',[
[psg.Frame(layout=[
[psg.Radio('ID/PW Only','account_info',key='-Only_T-',enable_events=True)],
[psg.Radio('Local Only','account_info',key='-Only_L-',enable_events=True)],
[psg.Radio('ID/PW and Local','account_info',key='-T_W_L-',circle_color='yellow', text_color='yellow',enable_events=True,default=True)]],
title='계정 모드 설정',vertical_alignment='t')]],vertical_alignment='c',element_justification='c',border_width=0),
psg.Frame('',[
[psg.Frame(layout=[[psg.Text(size=(18,1), justification='center',font=('Helvetica', 15, 'bold'),key='-datetime-')]],title='현재 시간')],
[psg.Frame(layout=[[psg.Text('제작자: 조성진',size=(18,1), justification='center',font=('Helvetica', 15, 'bold'))],
[psg.Text('문 의: dldlftktka@naver.com',size=(25,1), justification='center',font=('Helvetica', 12, 'bold'))],
],title='정보')]],element_justification='c',vertical_alignment='t',border_width=0,pad=(0,0))],
[psg.Frame(layout=[[psg.Input(size=(60,1),change_submits=True,key='-File-',disabled=True),
psg.FileBrowse(size=(10,1),file_types=(('xlsx File','*.xlsx'),))]],title='파일 찾기')],
[psg.Frame(layout=[[psg.Multiline(autoscroll=True,size=(70,20),key='-CommandLine-',rstrip=False)]],title='명령어 입력'),
psg.Frame('',[
[psg.Frame('',[
[psg.Frame(layout=[[psg.Text(size=(1,1))]],title='',border_width=0)],
[psg.Frame(layout=[[psg.Text(size=(1,1))]],title='',border_width=0)]],element_justification='c',border_width=0,pad=(0,50))],
[psg.Frame(layout=[[psg.Ok(size=(10,5)),psg.Exit(size=(10,5))]],title='',border_width=0,vertical_alignment='c')]]
,border_width=0,vertical_alignment='b',element_justification='c',pad=(30,10))]]
window = psg.Window('SSH 자동화 Tool v0.1 (paramiko)', layout, grab_anywhere=True, finalize=True) # make gui window
while True:
event, values = window.read(timeout=900) # Read the event that happened and the values dictionary
window['-datetime-'].update(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')) # time update
if event in (None, 'Exit', 'Quit'): # If user closeddow with X or if user clicked "Exit" button then exit
break
if values['-Only_T-']: # Tacacs 계정만 사용
window['-Only_T-'].update(circle_color='yellow', text_color='yellow')
window['-Only_L-'].update(circle_color='black', text_color='white')
window['-T_W_L-'].update(circle_color='black', text_color='white')
window['-TacacsID-'].update(disabled=False)
window['-TacacsPW-'].update(disabled=False)
window['-LocalID-'].update('',disabled=True)
window['-LocalPW-'].update('',disabled=True)
if values['-Only_L-']: # Local 계정만 사용
window['-Only_T-'].update(circle_color='black', text_color='white')
window['-Only_L-'].update(circle_color='yellow', text_color='yellow')
window['-T_W_L-'].update(circle_color='black', text_color='white')
window['-TacacsID-'].update('',disabled=True)
window['-TacacsPW-'].update('',disabled=True)
window['-LocalID-'].update(disabled=False)
window['-LocalPW-'].update(disabled=False)
if values['-T_W_L-']: # Tacacs 계정 및 Local 계정 사용
window['-Only_T-'].update(circle_color='black', text_color='white')
window['-Only_L-'].update(circle_color='black', text_color='white')
window['-T_W_L-'].update(circle_color='yellow', text_color='yellow')
window['-TacacsID-'].update(disabled=False)
window['-TacacsPW-'].update(disabled=False)
window['-LocalID-'].update(disabled=False)
window['-LocalPW-'].update(disabled=False)
if event == 'Ok':
Account_Mode = bool(values['-T_W_L-']) # 계정 모드 변수
pop_ch = psg.PopupOKCancel(""," 진행하시겠습니까? \x00", " 중지 할 수 없습니다. \x00", "", title='확인') # popup 공백 넣는 기술.. 1차원 배열이라 "","",""... 이런식임
if pop_ch == 'OK':
if values['-Port-'].isdigit():
try:
DEVICES, DEVICES_NAME, LOG_FILE_PATH, USER_TAC, PASSWD_TAC, USER_LOCAL, PASSWD_LOCAL, PORT, COMMAND = Run()
Error_File_Path = "%s\Error"%(LOG_FILE_PATH)
os.mkdir(Error_File_Path)
start = time.time()
window.hide() # 창 숨기기
err_div = Processing_Window()
if err_div.empty():
os.rmdir(Error_File_Path)
else:
error_log = open('%s\error_ip.txt'%Error_File_Path, "a+")
for i in range(err_div.qsize()):
error_log.write("%s\n"%err_div.get())
error_log.close()
window.un_hide() # 창 보이기
'''
try:
os.rmdir(Error_File_Path)
except:
pass
'''
end = (time.time() - start)
sec_result = str(datetime.timedelta(seconds=end)).split(".")
psg.popup("", " 완료 \x00", " 걸린 시간: %s(초) \x00"%sec_result[0], "",title='완료', font=(20), keep_on_top = True)
except Exception as e:
psg.popup("", " 정보를 다시 확인해주세요. \x00", "%s"%e,title='정보')
else:
psg.popup("", " 포트에는 숫자만 입력가능합니다. \x00", "",title='정보')
else:
psg.popup("", " 취소하였습니다. \x00", "",title='정보')
window.close()
sys.exit()
'Python' 카테고리의 다른 글
Fortigate 방화벽 전체 로그를 이용한 정책 추출 (0) | 2024.07.25 |
---|---|
netmiko cisco telnet 접속 프로그램 (수정2) (0) | 2024.01.24 |
netmiko ssh 접속 프로그램 (수정2) (0) | 2024.01.24 |
paramiko ssh 접속 개선판 (수정2) (0) | 2024.01.24 |
R&S 파이썬 자동화 개선판 (0) | 2023.03.03 |