@Lenciel

使用paramiko进行ssh工作

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

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

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

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

paramiko.SSHException: No suitable address

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

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

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

"""
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()

起飞之前

英语教员:Have you watched “Red Cliff”? 本组天才:Yes, long time ago. It’s a story in the war time. 英语教员:Yeah, tell us about the story… 本座(心里):What the fuck….There is no story in that shit… 本组天才:A revolution woman, Jiang Jie, she … 英语教员:Who? 本座:Who? 本组天才:Jiang Jie!

教员和本座面面相觑。然后大家终于憋不住要祭出中文了:

教员:Jiang Jie是谁啊?《赤壁》里面好像没有啊。 本组天才:啊,Red Cliff是《赤壁》?我以为是《红岩》。

然后,人家就准备坐上机机回成都鸟。宰小涛同学专门贡献了一砣采访事故,抄送给所有坚持观看在与业余球员比赛中折戟沉沙的中国男足的壮士:

CCAV记者:请问为虾米要换下表现一直非常出色的17号队员? 叙利亚主帅(非常诚恳滴):因为别个明天早上还要上班。