公司有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
    = struct.pack('HHHH'0000)
    = 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()
= open('passwd.txt')
num = 0
for 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