公司有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