본문 바로가기
Python

netmiko ssh 접속 프로그램 (수정2)

by Ao1 2024. 1. 24.

(신버전)

import os
import sys
sys.path.append(os.getcwd() + "\lib")

import pandas as pd
from netmiko import SSHDetect, ConnectHandler, NetmikoAuthenticationException, NetmikoTimeoutException
from paramiko.ssh_exception import SSHException
import PySimpleGUI as psg
import datetime
import threading
import concurrent.futures
import time

# 엑셀 읽어오기
def xlsx_read(pd_name):  
    pd_xlsx = pd.read_excel(pd_name, engine = "openpyxl", sheet_name=0)
   
    try:
        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, log_file_path
    except:
        psg.popup("", "          파일이 잘못되었습니다.          \x00", "",title='정보')

# Choice
def Run():
    if values['-Only_T-']:
        DEVICES,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, 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, 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, LOG_FILE_PATH, USER_TAC, PASSWD_TAC, USER_LOCAL, PASSWD_LOCAL, PORT, COMMAND

# 진행중 표시 창
def Processing_Window():
    complet = 0

    # SSH Connect
    def sessions(DEVICE, USER, PASSWD_SECRET, USER_LOCAL, PASSWD_LOCAL, PORT):
        lock = threading.Lock()
        nonlocal complet
       
        output = ''
       
        device = {'device_type': 'autodetect', 'host': DEVICE, 'port': PORT, 'username': USER, 'password': PASSWD_SECRET, 'secret': PASSWD_SECRET,
                'read_timeout_override': 300, 'verbose': False,} # read_timeout_override: 숫자는 초임 그 안에 # 안나오면 timeout except
       
        try:
            # device_type 찾는거임 공식 git 인용
            guesser = SSHDetect(**device)
            best_match = guesser.autodetect()
            device["device_type"] = best_match
           
            ssh_session = ConnectHandler(**device)
           
            hostname = ssh_session.find_prompt()[:-1]       # getting hostname
            hostname = hostname.rstrip()

            ssh_session.enable()        # enable 모드 진입
           
            Conf_ch = bool([s for s in COMMAND if 'conf' in s]) # 컨피그 모드 접속 명령어 있는지 확인
           
            # 컨피그 모드 명령어 있는지 검사하여 제거 * 있으면 오류 생김
            if Conf_ch:
                for x in COMMAND:
                    if 'conf' in x:
                        COMMAND.remove(x)
           
            #if Config_Mode or Conf_ch:
            #    ssh_session.config_mode()       # config 모드 진입
               
            output += ssh_session.send_multiline(COMMAND.split('\n'))        # 이렇게 안하면 한글자씩 명령어 들어감
           
            if Save_Mode:
                output += ssh_session.exit_config_mode()
                output += ssh_session.save_config()
           
            # log 파일 생성
            dev_log = open('%s\%s.log'%(LOG_FILE_PATH,hostname), "w")
            dev_log.write(output)
            dev_log.close()
           
            ssh_session.disconnect()
           
            lock.acquire()
            complet = complet + 1
            lock.release()
           
        except NetmikoAuthenticationException:
            if Account_Mode:
                sessions(DEVICE, USER_LOCAL, PASSWD_LOCAL, '', '', PORT)
            else:
                error_log = open('%s\error_ip.txt'%Error_File_Path, "a+")
                error_log.write("%s\n"%DEVICE)
                error_log.close()
               
                lock.acquire()
                complet = complet + 1
                lock.release()

        except (SSHException, NetmikoTimeoutException, TimeoutError):
            error_log = open('%s\error_ip.txt'%Error_File_Path, "a+")
            error_log.write("%s\n"%DEVICE)
            error_log.close()
           
            lock.acquire()
            complet = complet + 1
            lock.release()


        except:
            error_log = open('%s\error_ip.txt'%Error_File_Path, "a+")
            error_log.write("%s\n"%DEVICE)
            error_log.close()
           
            lock.acquire()
            complet = complet + 1
            lock.release()

###################################################################################################################################################    
    # SSH 스레싱
    def SSH_Threading():
        dc = 0
        thrs = []
                           
        while dc < len(DEVICES):
            time.sleep(0.5)
           
            thread_2 = threading.Thread(target=sessions, args=(DEVICES[dc], USER_TAC, PASSWD_TAC, USER_LOCAL, PASSWD_LOCAL, PORT))
            thread_2.start()
            dc += 1
           
            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=100) # 1초

        # 스레드 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()

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')],
                   [psg.Frame('',[
                       #[psg.Frame(layout=[
                       #[psg.Checkbox('Config Mode 꺼짐',key='-mode_ct-', enable_events=True,font=('any',10,'bold'))]]
                       #           ,title='장비 모드 설정', vertical_alignment='c',element_justification='c')],
                       [psg.Frame(layout=[
                       [psg.Checkbox('저장 안함',key='-save-', enable_events=True,font=('any',10,'bold'))]]
                                  ,title='저장 여부 확인', vertical_alignment='c',element_justification='c')]]
                              ,vertical_alignment='c',element_justification='c',border_width=0)]],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('문 의: ㅁㅁㅁ',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', 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 values['-mode_ct-']:
        #    window['-mode_ct-'].update(text='Config Mode 켜짐',text_color='yellow')
       
        #if not values['-mode_ct-']:
        #    window['-mode_ct-'].update(text='Config Mode 꺼짐',text_color='white')
       
        if values['-save-']:
            window['-save-'].update(text='    저장    ',text_color='red')
       
        if not values['-save-']:
            window['-save-'].update(text='저장 안함',text_color='white')
           
        if event == 'Ok':
            #Config_Mode = bool(values['-mode_ct-'])     # 컨피그 모드 변수
            Account_Mode = bool(values['-T_W_L-'])      # 계정 모드 변수
            Save_Mode = bool(values['-save-'])      # 저장 모드 변수
           
            pop_ch = psg.PopupOKCancel("","                 진행하시겠습니까?                 \x00", "                 중지 할 수 없습니다.                 \x00", "", title='확인')        # popup 공백 넣는 기술.. 1차원 배열이라 "","",""... 이런식임
            if pop_ch == 'OK':
                if values['-Port-'].isdigit():
                    try:    
                        DEVICES, 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() # 창 숨기기
                       
                        Processing_Window()
                       
                        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:
                        psg.popup("", "          정보를 다시 확인해주세요.          \x00", "",title='정보')
                else:
                    psg.popup("", "          포트에는 숫자만 입력가능합니다.          \x00", "",title='정보')
            else:
                psg.popup("", "          취소하였습니다.          \x00", "",title='정보')
                   
               
                           
    window.close()

 

(구버전)

import os
import sys
sys.path.append(os.getcwd() + "\lib")

import pandas as pd
from netmiko import SSHDetect, ConnectHandler, NetmikoAuthenticationException, NetmikoTimeoutException
from paramiko.ssh_exception import SSHException
import PySimpleGUI as psg
import datetime
import threading
import concurrent.futures
import time


# SSH Connect
def sessions(DEVICE, USER, PASSWD_SECRET, USER_LOCAL, PASSWD_LOCAL, PORT):
    output = ''
   
    device = {'device_type': 'autodetect', 'host': DEVICE, 'port': PORT, 'username': USER, 'password': PASSWD_SECRET, 'secret': PASSWD_SECRET,
              'read_timeout_override': 300, 'verbose': False,} # read_timeout_override: 숫자는 초임 그 안에 # 안나오면 timeout except
     
    try:
        # device_type 찾는거임 공식 git 인용
        guesser = SSHDetect(**device)
        best_match = guesser.autodetect()
        device["device_type"] = best_match
       
        ssh_session = ConnectHandler(**device)
       
        hostname = ssh_session.find_prompt()[:-1]       # getting hostname
        hostname = hostname.rstrip()

        ssh_session.enable()        # enable 모드 진입
       
        Conf_ch = bool([s for s in COMMAND if 'conf' in s]) # 컨피그 모드 접속 명령어 있는지 확인
       
        # 컨피그 모드 명령어 있는지 검사하여 제거 * 있으면 오류 생김
        if Conf_ch:
            for x in COMMAND:
                if 'conf' in x:
                    COMMAND.remove(x)
       
        if Config_Mode or Conf_ch:
            ssh_session.config_mode()       # config 모드 진입
           
        output += ssh_session.send_multiline(COMMAND.split('\n'))        # 이렇게 안하면 한글자씩 명령어 들어감
       
        if Save_Mode:
            output += ssh_session.exit_config_mode()
            output += ssh_session.save_config()

               
        # log 파일 생성
        dev_log = open('%s\%s.log'%(LOG_FILE_PATH,hostname), "w")
        dev_log.write(output)
        dev_log.close()
       
        ssh_session.disconnect()
       
    except NetmikoAuthenticationException:
        if Account_Mode:
            sessions(DEVICE, USER_LOCAL, PASSWD_LOCAL, '', '', PORT)
        else:
            error_log = open('%s\error_ip.txt'%Error_File_Path, "a+")
            error_log.write("%s\n"%DEVICE)
            error_log.close()

    except (SSHException, NetmikoTimeoutException, TimeoutError):
        error_log = open('%s\error_ip.txt'%Error_File_Path, "a+")
        error_log.write("%s\n"%DEVICE)
        error_log.close()

    except:
        error_log = open('%s\error_ip.txt'%Error_File_Path, "a+")
        error_log.write("%s\n"%DEVICE)
        error_log.close()


# SSH Processing
def SSH_Processing():
    dc = 0
    thrs = []
                   
    while dc < len(DEVICES):
        thread_2 = threading.Thread(target=sessions, args=(DEVICES[dc], USER_TAC, PASSWD_TAC, USER_LOCAL, PASSWD_LOCAL, PORT))
        thread_2.start()
        dc += 1
       
        thrs.append(thread_2)
       
    for thr in thrs:
        thr.join()
                           
   
   
   
# 엑셀 읽어오기
def xlsx_read(pd_name):  
    pd_xlsx = pd.read_excel(pd_name, engine = "openpyxl", sheet_name=0)
   
    try:
        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, log_file_path
    except:
        psg.popup("", "          파일이 잘못되었습니다.          \x00", "",title='정보')


# Choice
def Run():
    if values['-Only_T-']:
        DEVICES,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, 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, 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, LOG_FILE_PATH, USER_TAC, PASSWD_TAC, USER_LOCAL, PASSWD_LOCAL, PORT, COMMAND
   


# 진행중 표시 창
def Processing_Window():
    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)
   
    char_ch_count = 1

    while True:
        event, values = window_1.read(timeout=1000) # 1초
       
        # 중지
        if event == '-Stop-':
            sys.exit()

        # 스레드 1번이 살아 있으면 조건문 수행
        if thread_1.is_alive():
            if (char_ch_count%3) == 1:
                window_1['-now-'].update('진행중.   %s'%char_ch_count)
               
            if (char_ch_count%3) == 2:
                window_1['-now-'].update('진행중..  %s'%char_ch_count)
               
            if (char_ch_count%3) == 0:
                window_1['-now-'].update('진행중... %s'%char_ch_count)
               
            char_ch_count += 1
            continue
        else:
            break
       
    window_1.close()
   
    return char_ch_count

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')],
                   [psg.Frame('',[
                       [psg.Frame(layout=[
                       [psg.Checkbox('Config Mode 꺼짐',key='-mode_ct-', enable_events=True,font=('any',10,'bold'))]]
                                  ,title='장비 모드 설정', vertical_alignment='c',element_justification='c')],
                       [psg.Frame(layout=[
                       [psg.Checkbox('저장 안함',key='-save-', enable_events=True,font=('any',10,'bold'))]]
                                  ,title='저장 여부 확인', vertical_alignment='c',element_justification='c')]]
                              ,vertical_alignment='c',element_justification='c',border_width=0)]],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.Image('lib\Dev\img.png')]],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', 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 values['-mode_ct-']:
            window['-mode_ct-'].update(text='Config Mode 켜짐',text_color='yellow')
       
        if not values['-mode_ct-']:
            window['-mode_ct-'].update(text='Config Mode 꺼짐',text_color='white')
       
        if values['-save-']:
            window['-save-'].update(text='    저장    ',text_color='red')
       
        if not values['-save-']:
            window['-save-'].update(text='저장 안함',text_color='white')
           
        if event == 'Ok':
            Config_Mode = bool(values['-mode_ct-'])     # 컨피그 모드 변수
            Account_Mode = bool(values['-T_W_L-'])      # 계정 모드 변수
            Save_Mode = bool(values['-save-'])      # 저장 모드 변수
           
            pop_ch = psg.PopupOKCancel("","                 진행하시겠습니까?                 \x00", "                 중지 할 수 없습니다.                 \x00", "", title='확인')        # popup 공백 넣는 기술.. 1차원 배열이라 "","",""... 이런식임
            if pop_ch == 'OK':
                if values['-Port-'].isdigit():
                    try:    
                        DEVICES, 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()
                       
                        # SSH 접속 스레드
                        thread_1 = threading.Thread(target=SSH_Processing)
                        thread_1.start()

                        window.hide() # 창 숨기기
                       
                        Wait_Time = Processing_Window()
                       
                        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:
                        psg.popup("", "          정보를 다시 확인해주세요.          \x00", "",title='정보')
                else:
                    psg.popup("", "          포트에는 숫자만 입력가능합니다.          \x00", "",title='정보')
            else:
                psg.popup("", "          취소하였습니다.          \x00", "",title='정보')
                   
               
                           
    window.close()