公司有1000多台服务器,线上机器都是禁止root登录的,所以平时是用普通用户登录,然后在su到root,密码都是在excel表中存的,这样登录一台机器,输两次命令,搜两次密码,实在很麻烦,而且密码表都在大家手中不易控制,所以把密码放到数据库中,每次ssh登录自动去数据库中查密码,然后发送密码,实现交互,这样既方便了我们,又控制的密码,脚本的核心是用pexpect来实现交互,用MySQLdb去查询密码,把代码保存为zssh 给个执行权限,建立数据库,把密码表导入到数据库中,就可以使用zssh ip 来登录了,是不是很爽,来试试吧!
pexpect的用法看
代码见附件
代码如下:
#!/usr/local/bin/python# coding: utf-8##导入模块import osimport sysimport pexpectimport MySQLdbimport structimport fcntlimport termiosimport 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]##传入的ipip = opt[1]##用MySQLdb驱动连接mysqlconn = 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类,连接sshfoo = 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
数据库建立
create database sa;create table password (ip varchar(15) primary key not null, muser varchar(15), mpass varchar(30), rpass varchar(30));
将密码表的中的ip,普通用户名,密码,root密码插入库中我用的是一个脚本
#!/usr/local/bin/pythonimport MySQLdbconn = MySQLdb.connect(host='localhost', user='root', passwd='Te62S#^t', db='sa')cursor = conn.cursor()f = open('passwd.txt')num = 0for 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: passprint 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