公司有1000多台服务器,线上机器都是禁止root登录的,所以平时是用普通用户登录,然后在su到root,密码都是在excel表中存的,这样登录一台机器,输两次命令,搜两次密码,实在很麻烦,而且密码表都在大家手中不易控制,所以把密码放到数据库中,每次ssh登录自动去数据库中查密码,然后发送密码,实现交互,这样既方便了我们,又控制的密码,脚本的核心是用pexpect来实现交互,用MySQLdb去查询密码,把代码保存为zssh 给个执行权限,建立数据库,把密码表导入到数据库中,就可以使用zssh ip 来登录了,是不是很爽,来试试吧!

pexpect的用法看http://www.ibm.com/developerworks/cn/linux/l-cn-pexpect1/

代码见附件

代码如下:

#!/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


数据库建立

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/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