先日から作成しているPythonでの選択肢型ssh自動接続スクリプト、なんとかタイムスタンプ付きのログを取得出来るよう改良した。
まぁ、一時ファイルを作成してタイムスタンプを付与、しかもtailのラッパースクリプトとして動作させているので、あまり納得はいってないんだけど…一応動くし、まぁいいか。どうせMacかLinuxでしか動かさないし。
1.host.list
host.listについては、前回作成した内容から変わらない。
host.list
# SSHAutoLogin.ttl用 ログインホスト設定ファイル
# 左から順に、以下の内容を記述していく。
# HOST_NAME(任意の名称。接続するホストの選択時やログ名に利用する。必須。)
# HOST_IP(ホストのIPアドレス。接続時に利用する。必須。)
# KEY_FILE(鍵ファイルの設置PATH。ない場合は空欄で記述。)
# HOST_ROOT_USER(管理者ユーザ名。ログインユーザを設定してスイッチする場合はrootユーザを設定。必須。)
# HOST_ROOT_PASS(管理者ユーザパスワード。必須。)
# HOST_USER(ログインユーザ名。管理者ユーザで直接ログイン出来る場合は不要。)
# HOST_PASS(ログインユーザパスワード。管理者ユーザで直接ログイン出来る場合は不要。)
# SUDO_FLAG(スイッチ文を「sudo su -」とするか否か。何かしら(0でも1でも)入力すると有効になる。スイッチ時のコマンドが「su -」の場合は不要)
# HOST_NAME, HOST_IP, KEY_FILE, HOST_ROOT_USER, HOST_ROOT_PASS, HOST_USER, HOST_PASS, SUDO_FLAG
# CentOS(「su -」)でスイッチする例
Test-CentOS1,172.28.0.101,,root,password,test,password
# CentOS(「su -」)でスイッチせずに直接ログインする例
Test-CentOS2,172.28.0.102,,root,password
# Ubuntu(sudo su -)でスイッチする例
Test-Ubuntu1,172.28.0.103,,test,password,test,password,1
# AWSテスト
AWSテスト,XXX.XXX.XXX.XXX,/tmp/test.pem,centos,
2.ssh_connect.py
ssh_connect.pyについては、Teratermログのようなタイムスタンプ付きのログを取得させるようにした。
ssh_connect.py
#! /usr/bin/python
# -*- coding: utf-8 -*-
# +-------------------------------------------+
# + +
# + +
# +-------------------------------------------+
################
# モジュール読込 #
################
from __future__ import division #You don't need this in Python3
import curses
from math import *
import os
import pexpect
import locale
locale.setlocale(locale.LC_ALL, "")
from datetime import datetime
import subprocess
######
# 関数 #
######
def ssh_connect(line_no):
# 接続時に使用する情報を取得
connect_host_name = "".join(map(str,host_name_list[line_no]))
connect_host_ip = "".join(map(str,host_ip_list[line_no]))
connect_key_file = "".join(map(str,key_file_list[line_no]))
connect_host_root_user = "".join(map(str,host_root_user_list[line_no]))
connect_host_root_pass = "".join(map(str,host_root_pass_list[line_no]))
connect_host_user = "".join(map(str,host_user_list[line_no]))
connect_host_pass = "".join(map(str,host_pass_list[line_no]))
connect_sudo_flag = "".join(map(str,sudo_flag_list[line_no]))
# 一時ログファイル、正規ログファイル定義
pid = str(os.getpid())
tmp_log = tmp_dir + '.' + pid + '.' + connect_host_name + '.' + now_time
terminal_log = log_dir + now_time + '_' + connect_host_name + '.log'
# ログインユーザーの指定有無を確認
if connect_host_user == "":
connect_user = connect_host_root_user
connect_pass = connect_host_root_pass
else:
connect_user = connect_host_user
connect_pass = connect_host_pass
if connect_key_file == "":
foo = pexpect.spawn('ssh -o "StrictHostKeyChecking=no" %s@%s' % (connect_user, connect_host_ip))
else:
foo = pexpect.spawn('ssh -o "StrictHostKeyChecking=no" -i %s %s@%s' % (connect_key_file, connect_user, connect_host_ip))
# ログの取得開始
foo.logfile_read = open(tmp_log,"w")
log_tail = 'tail -f ' + tmp_log
log_awk = 'gawk \'{ print strftime("[%Y/%m/%d %H:%M:%S]") " " $0 } {system (" ")}\' >' + terminal_log
get_log_command = log_tail + ' | ' + log_awk + ' &'
#subprocess.Popen(get_log_command, shell=True)
os.system(get_log_command)
if not connect_pass == "":
foo.expect(['.*ssword:','パスワード:'])
print foo.before.rstrip()
print foo.after.rstrip()
foo.sendline(connect_pass)
if not connect_host_user == "":
foo.expect(['$','#'])
print foo.before.strip()
print foo.after.strip()
foo.sendline('su - %s' % (connect_host_root_user))
foo.expect(['.*ssword:','パスワード:'])
print foo.before.strip()
print foo.after.strip()
foo.sendline(connect_host_root_pass)
foo.interact()
#os.system('kill ' + log_pid + ' &')
os.system('ps -fC "tail" | grep "' + log_tail + '" | awk \'{ print $2\'} | xargs kill')
os.remove(tmp_log)
##########
# 設定関連 #
##########
max_row = 20
list_file = '/root/data.csv'
command_file = ''
log_dir = '/work/'
tmp_dir = '/tmp/'
now_time = datetime.now().strftime('%Y%m%d_%H%M%S')
################
# curses関連設定 #
################
# リスト表示件数
screen = curses.initscr()
curses.noecho()
curses.cbreak()
curses.start_color()
screen.keypad( 1 )
curses.init_pair(1,curses.COLOR_BLACK, curses.COLOR_CYAN)
highlightText = curses.color_pair( 1 )
normalText = curses.A_NORMAL
screen.border( 0 )
curses.curs_set( 0 )
box = curses.newwin( max_row + 2, 100, 1, 1 )
box.box()
################
# リスト情報取得 #
################
f = open(list_file)
line = f.readline()
i = 0
host_name_list = []
host_ip_list = []
key_file_list = []
host_root_user_list = []
host_root_pass_list = []
host_user_list = []
host_pass_list = []
sudo_flag_list = []
while line:
line = line.strip()
# コメント・空行を除外
if line.startswith( "#" ) or len( line ) == 0:
line = f.readline()
continue
# リストの各要素を取得
line_column = len( line.split(',') )
if line_column == 5:
host_name = line.split(',')[0]
host_ip = line.split(',')[1]
key_file = line.split(',')[2]
host_root_user = line.split(',')[3]
host_root_pass = line.split(',')[4]
host_user = ""
host_pass = ""
sudo_flag = ""
elif line_column == 7:
host_name = line.split(',')[0]
host_ip = line.split(',')[1]
key_file = line.split(',')[2]
host_root_user = line.split(',')[3]
host_root_pass = line.split(',')[4]
host_user = line.split(',')[5]
host_pass = line.split(',')[6]
sudo_flag = ""
elif line_column == 8:
host_name = line.split(',')[0]
host_ip = line.split(',')[1]
key_file = line.split(',')[2]
host_root_user = line.split(',')[3]
host_root_pass = line.split(',')[4]
host_user = line.split(',')[5]
host_pass = line.split(',')[6]
sudo_flag = line.split(',')[7]
else:
curses.endwin()
print "リストに誤りがあります。"
print line
exit(1)
host_name_list += [[host_name]]
host_ip_list += [[host_ip]]
key_file_list += [[key_file]]
host_root_user_list += [[host_root_user]]
host_root_pass_list += [[host_root_pass]]
host_user_list += [[host_user]]
host_pass_list += [[host_pass]]
sudo_flag_list += [[sudo_flag]]
line = f.readline()
f.close
row_num = len( host_name_list )
############
# リスト表示 #
############
pages = int( ceil( row_num / max_row ) )
position = 1
page = 1
for i in range( 1, max_row + 1 ):
if row_num == 0:
box.addstr( 1, 1, "There aren't host_name_list", highlightText )
else:
if (i == position):
box.addstr( i, 2, str( i ) + " - " + "".join(map(str,host_name_list[ i - 1 ])), highlightText )
else:
box.addstr( i, 2, str( i ) + " - " + "".join(map(str,host_name_list[ i - 1 ])), normalText )
if i == row_num:
break
screen.refresh()
box.refresh()
########################
# ホスト選択画面キー操作 #
########################
x = screen.getch()
while x != 27:
# 下キー押下時の動作
if x == curses.KEY_DOWN:
if page == 1:
if position < i:
position = position + 1
else:
if pages > 1:
page = page + 1
position = 1 + ( max_row * ( page - 1 ) )
elif page == pages:
if position < row_num:
position = position + 1
else:
if position < max_row + ( max_row * ( page - 1 ) ):
position = position + 1
else:
page = page + 1
position = 1 + ( max_row * ( page - 1 ) )
# 上キー押下時の動作
if x == curses.KEY_UP:
if page == 1:
if position > 1:
position = position - 1
else:
if position > ( 1 + ( max_row * ( page - 1 ) ) ):
position = position - 1
else:
page = page - 1
position = max_row + ( max_row * ( page - 1 ) )
# 左キー押下時の動作
if x == curses.KEY_LEFT:
if page > 1:
page = page - 1
position = 1 + ( max_row * ( page - 1 ) )
# 右キー押下時の動作
if x == curses.KEY_RIGHT:
if page < pages:
page = page + 1
position = ( 1 + ( max_row * ( page - 1 ) ) )
# Enter押下時(決定)の処理
if x == ord( "\n" ) and row_num != 0:
screen.erase()
screen.border( 0 )
curses.endwin()
ssh_connect(position - 1)
exit()
box.erase()
screen.border( 0 )
box.border( 0 )
for i in range( 1 + ( max_row * ( page - 1 ) ), max_row + 1 + ( max_row * ( page - 1 ) ) ):
if row_num == 0:
box.addstr( 1, 1, "There aren't host_name_list", highlightText )
else:
if ( i + ( max_row * ( page - 1 ) ) == position + ( max_row * ( page - 1 ) ) ):
box.addstr( i - ( max_row * ( page - 1 ) ), 2, str( i ) + " - " + "".join(map(str,host_name_list[ i - 1 ])), highlightText )
else:
box.addstr( i - ( max_row * ( page - 1 ) ), 2, str( i ) + " - " + "".join(map(str,host_name_list[ i - 1 ])), normalText )
if i == row_num:
break
screen.refresh()
box.refresh()
x = screen.getch()
curses.endwin()
exit()
うーん、処理の仕方が汚いのが気になるけど、とりあえずはこれでいいか…
そのうち直そう。