@Lenciel

使用paramiko进行ssh工作

最近在单位写一个自动build的小工具。因为clearcase的setview命令实际上是激活一个新的shell,所以用简单的“串通”shell的脚本很难做到。

因为在邮件组里面看到有同样问题的Matt说用paramiko解决了问题,就试了试,过程还颇有点艰辛。

首先,paramiko没有直接的msi或者exe版本给Windows用户下载,而是需要在本地进行编译。而且pythoneasy_install工具在Vista下面会报错,所以至少花了十几分钟才算安装完毕。

结果在用test.py验证安装的时候就报错了,说什么:

1
paramiko.SSHException: No suitable address

安装是我自己一步步弄得,难道搞错了?只好照着demo写了一个sftp的脚本,发现是可以跑的,干。

只好丢了封信给邮件组,然后自己开始找是啥问题。丢给邮件组的信至今没有回音(人气不行啊,paramiko),问题还是找到了。原来是1.7.5的paramiko增加了对ipv6的支持,结果引入了错误。更新了client.py后重新编译就可以用了。

最后,虽然demo的例子也挺多,但是好像没有说清楚怎么用invoke_shell和get_pty以及照例奉上一段代码。

(paramiko_sample.py) download
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
131
132
133
134
135
136
137
138
139
140
141
142
"""
This script is using for build the software package
"""

import sys
import time
import paramiko
import traceback
import ConfigParser

"""
The main class of the builder.
"""
class Builder:

    """Parses options from the ini file to create connection."""
    def __init__(self,inifile):
        try:
            config = ConfigParser.ConfigParser()
            config.readfp(open(inifile))

            self._ssh = paramiko.SSHClient()
            self._ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            self._ssh.connect(config.get('host','server'),
                              port=config.getint('host', 'port'),
                              username=config.get('host','user'),
                              password=config.get('host','password'))

            self._t = paramiko.Transport((config.get('host','server'), config.getint('host', 'port')))
            self._t.start_client()
            self._t.auth_password(config.get('host','user'),config.get('host','password'))
            self._sftp = paramiko.SFTPClient.from_transport(self._t)
        except Exception, e:
            print '*** Caught exception: %s: %s' % (e.__class__, e)
            traceback.print_exc()
            try:
                self.closeConn()
            except:
                pass
            sys.exit(1)

        self._fpga = config.get('fpga compress','fpga')
        self._lpath = config.get('fpga compress','local_fpga_path')
        self._rpath = config.get('fpga compress','remote_fpga_path')
        self._oab = config.get('fpga compress','oab')

        self._xlf = config.get('xlf build','xlf')
        self._lmid = config.get('xlf build','lmid')
        self._xpp = config.get('xlf build','xpp')
        self._xdp = config.get('xlf build','xdp')
        self._rru = config.get('xlf build','rru')
        self._rruswdb = config.get('xlf build','rru_sw_db')
        self._xpl = config.get('xlf build','xpl')
        print("Your input fpga file is:"+self._lpath+self._fpga+"\n")
        print("Your ouput xlf file will be:"+self._xlf+"\n")

    """Run command on the server"""
    def runCmd(self, command):
        """run <command>
        Execute this command on all hosts in the list"""
        if command:
            stdin, stdout, stderr = self._ssh.exec_command(command)
            stdin.close()
            for line in stdout.read().splitlines():
                print line
        else:
            print "usage: run <command>"

    """Upload the fpga and compress it to oab.bin"""
    def createOab(self):
        self._sftp.put(self._lpath+self._fpga,self._rpath+self._fpga)

        self.runCmd("hou_create_fpga -bf \"/home/ehholli/fpgainput/fpga.med\" -dn \"CXC 172 8213/1\" -of oab -dev \"XC2V6000,-4\" -dir /home/ehholli/fpgaoutput/")
        try:
            self._sftp.get(self._oab,'oab.bin')
            print("Fpga file compress successfully!")
        except Exception, e:
            print '*** Caught exception: %s: %s' % (e.__class__, e)
            traceback.print_exc()
            try:
                self.closeConn()
            except:
                pass
            sys.exit(1)

    """Make the tlf"""
    def genXlf(self):
        #open a interactive shell
        ct_chan = self._t.open_session()
        ct_chan.setblocking()
        ct_chan.get_pty()
        ct_chan.invoke_shell()
        #ct setview ehholli
        if(ct_chan.send_ready()):
            ct_chan.send("ct setview ehholli\r\n")
        time.sleep(10)

        #compile
        build_cmd="/vobs/rbs/hw/bcp/xp/deliv/solaris2/bin/xlf_gen -r "+self._xpp+" "+self._xdp+" "+self._rru \
                     +" -i "+self._oab+" "+self._rruswdb \
                     +" -o /home/ehholli/tmp/"+self._xlf \
                     +" -x "+self._xpl \
                     +" -lmid \""+self._lmid+"\"" \
                     +" -t \"au_applic\" -v \r\n"
        print(build_cmd)
        if(ct_chan.send_ready()):
            ct_chan.send(build_cmd)
        tCheck2 =
        while not ct_chan.recv_ready():
            time.sleep(5)
            tCheck2+=1
            if tCheck2 >= 6:
                print 'time out'#TODO: add exeption here
        print(ct_chan.recv(65536))
        ct_chan.close()
        time.sleep(10)
        #download the xlf file
        try:
            self._sftp.get("/home/ehholli/tmp/"+self._xlf,self._xlf)
            print("xlf file downloaded successfully!")
        except Exception, e:
            print '*** Caught exception: %s: %s' % (e.__class__, e)
            traceback.print_exc()
            try:
                self.closeConn()
            except:
                pass
            sys.exit(1)

    """Close everything we opened"""
    def closeConn(self):
        self._ssh.close()
        self._sftp.close()
        self._t.close()
if __name__=='__main__':
    # setup logging
    paramiko.util.log_to_file('demo_builder.log')
    b=Builder('cfg.ini')
    b.createOab()
    b.genXlf()
    #b.runCmd('ls')
    b.closeConn()