公司有1000多台服務器,線上機器都是禁止root登錄的,所以平時是用普通用戶登錄,然后在su到root,密碼都是在excel表中存的,這樣登錄一台機器,輸兩次命令,搜兩次密碼,實在很麻煩,而且密碼表都在大家手中不易控制,所以把密碼放到數據庫中,每次ssh登錄自動去數據庫中查密碼,然后發送密碼,實現交互,這樣既方便了我們,又控制的密碼,腳本的核心是用pexpect來實現交互,用MySQLdb去查詢密碼,把代碼保存為zssh 給個執行權限,建立數據庫,把密碼表導入到數據庫中,就可以使用zssh ip 來登錄了,是不是很爽,來試試吧!
pexpect的用法看http://www.ibm.com/developerworks/cn/linux/l-cn-pexpect1/
代碼見附件
代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
#!/usr/local/bin/python
# coding: utf-8
##導入模塊
import
os
import
sys
import
pexpect
import
MySQLdb
import
struct
import
fcntl
import
termios
import
signal
##傳入的參數
opt
=
sys.argv
##如果沒跟參數,就提示
if
len
(opt)
=
=
1
:
print
'''
----------------------------
'Useage: ./zssh.py ServerIP'
----------------------------
'''
sys.exit(
2
)
##下面兩個函數更改pexpect模擬的窗口大小,
##參見http://guweigang.com/blog/2012/10/25/using-python-ssh-landing-module-performs-pexpect/
def
sigwinch_passthrough (sig, data):
winsize
=
getwinsize()
global
foo
foo.setwinsize(winsize[
0
],winsize[
1
])
def
getwinsize():
if
'TIOCGWINSZ'
in
dir
(termios):
TIOCGWINSZ
=
termios.TIOCGWINSZ
else
:
TIOCGWINSZ
=
1074295912L
# Assume
s
=
struct.pack(
'HHHH'
,
0
,
0
,
0
,
0
)
x
=
fcntl.ioctl(sys.stdout.fileno(), TIOCGWINSZ, s)
return
struct.unpack(
'HHHH'
, x)[
0
:
2
]
##傳入的ip
ip
=
opt[
1
]
##用MySQLdb驅動連接mysql
conn
=
MySQLdb.connect(host
=
'localhost'
, user
=
'root'
, passwd
=
'Te62S#^t'
, db
=
'sa'
)
cursor
=
conn.cursor()
##查找該ip的普通用戶名,密碼,還有root的密碼,用來ssh連接
cursor.execute(
'select muser,mpass,rpass from password where ip=%s'
, ip)
result
=
cursor.fetchall()
##如果沒在數據庫中發現該ip信息,提示用戶輸入,並保存,如果發現就准備連接
if
len
(result)
=
=
0
:
muser
=
raw_input
(
'輸入用戶名:'
)
mpass
=
raw_input
(
'輸入用戶密碼: '
)
rpass
=
raw_input
(
'輸入root密碼: '
)
cursor.execute(
'insert into password values (%s,%s,%s,%s)'
, (ip, muser, mpass, rpass))
conn.commit()
elif
len
(result)
=
=
1
:
muser
=
result[
0
][
0
]
mpass
=
result[
0
][
1
]
rpass
=
result[
0
][
2
]
##用pexpect模塊的spawn類,連接ssh
foo
=
pexpect.spawn(
'ssh %s@%s'
%
(muser,ip))
while
True
:
##期望得到列表里的東西
index
=
foo.expect([
'continue'
,
'assword'
, pexpect.EOF, pexpect.TIMEOUT],timeout
=
10
)
##如果得到的是continue,也就是第一次連接輸入yes/no那,那就發送yes
if
index
=
=
0
:
foo.sendline(
'yes'
)
continue
##如果是提示輸入password,那就發送密碼
elif
index
=
=
1
:
foo.sendline(mpass)
##發送密碼后有兩種情況,登錄成功或密碼錯誤
index2
=
foo.expect([
'password'
,
']\$'
])
##如果得密碼正確
if
index2
=
=
1
:
print
'%s 登錄成功'
%
muser
break
##如果密碼錯誤,提示輸入密碼
elif
index2
=
=
0
:
while
True
:
muser
=
raw_input
(
'輸入用戶名:'
)
mpass
=
raw_input
(
'用戶密碼不對,重新輸入: '
)
foo.sendline(mpass)
index3
=
foo.expect([
']\$'
,
'assword'
], timeout
=
5
)
##如果密碼對了,就保存到數據庫
if
index3
=
=
0
:
cursor.execute(
'update sys_pass set muser=%s, mpass=%s where ip=%s '
, (muser, mpass, ip))
conn.commit()
foo.sendline('')
break
##如果不對,再循環一次
else
:
continue
else
:
print
'連接超時'
break
##下面su 到root與上面類似
while
True
:
foo.expect(
'$'
)
foo.sendline(
'su - root'
)
#index4 = foo.expect(['口令', '密碼', 'assword', pexpect.TIMEOUT, pexpect.EOF],timeout=5)
foo.sendline(rpass)
index5
=
foo.expect([
']#'
,
'monitor'
, pexpect.EOF, pexpect.TIMEOUT], timeout
=
5
)
if
index5
=
=
0
:
print
'root 登錄成功'
foo.sendline('')
break
elif
index5
=
=
1
:
while
True
:
rpass
=
raw_input
(
'root密碼不對,請輸入: '
)
foo.expect(
'$'
)
foo.sendline(
'su - root'
)
#index6 = foo.expect(['口令', '密碼', 'assword', pexpect.TIMEOUT, pexpect.EOF],timeout=5)
foo.sendline(rpass)
index7
=
foo.expect([
']#'
,
'monitor'
, pexpect.EOF, pexpect.TIMEOUT], timeout
=
5
)
if
index7
=
=
0
:
cursor.execute(
'update sys_pass set rpass=%s where ip=%s'
, (rpass, ip))
conn.commit()
print
'root 登錄成功'
break
elif
index7
=
=
1
:
continue
else
:
print
'error'
else
:
print
'error'
##這個是利用那兩個函數來調節子線程窗口大小
signal.signal(signal.SIGWINCH, sigwinch_passthrough)
size
=
getwinsize()
foo.setwinsize(size[
0
], size[
1
])
##進入interact交互模式
foo.interact()
pass
|
數據庫建立
1
2
|
create
database
sa;
create
table
password
(ip
varchar
(15)
primary
key
not
null
, muser
varchar
(15), mpass
varchar
(30), rpass
varchar
(30));
|
將密碼表的中的ip,普通用戶名,密碼,root密碼插入庫中我用的是一個腳本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#!/usr/local/bin/python
import
MySQLdb
conn
=
MySQLdb.connect(host
=
'localhost'
, user
=
'root'
, passwd
=
'Te62S#^t'
, db
=
'sa'
)
cursor
=
conn.cursor()
f
=
open
(
'passwd.txt'
)
num
=
0
for
i
in
f:
ilist
=
i.split()
if
len
(ilist)
=
=
4
:
ip
=
ilist[
0
]
muser
=
ilist[
1
]
mpass
=
ilist[
2
]
rpass
=
ilist[
3
]
try
:
cursor.execute(
'insert into password values (%s,%s,%s,%s)'
, (ip, muser, mpass, rpass))
num
+
=
1
except
:
pass
print
num
conn.commit()
cursor.close()
conn.commit()
|
將密碼保存到passwd.txt格式類下面的格式,執行腳本就可以了
IP 普通用戶名 密碼 root密碼
202.106.0.20 monitor asdf123Sfad f(adfasdfasdf
202.106.0.21 zhswred hathell oworld