paramiko ssh客户端无法与HP交换机一起使用

时间:2013-07-19 13:49:12

标签: python python-2.7 ssh paramiko

我一直在使用我的脚本用于unix服务器,它运行良好。但是,当我使用相同的脚本(通过一些次要的命令更改)连接到HP Procurve交换机时,脚本会因错误而崩溃。部分脚本如下:

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(address, username=userna, password=passwd)

stdin,stdout,stderr= ssh.exec_command("show ver")

for line in stdout:
    print '... ' + line.strip('\n')

ssh.close()

这会产生错误

Traceback (most recent call last):
File "C:/Users/kucar/Desktop/my_python/switchmodel", line 34, in <module>
stdin,stdout,stderr= ssh.exec_command("show ver")
File "C:\Python27\lib\site-packages\paramiko\client.py", line 379, in exec_command
chan.exec_command(command)
File "C:\Python27\lib\site-packages\paramiko\channel.py", line 218, in exec_command
self._wait_for_event()
File "C:\Python27\lib\site-packages\paramiko\channel.py", line 1122, in _wait_for_event
raise e
SSHException: Channel closed.

我在网上发现了类似的抱怨,但似乎根本没有提供解决方案。开关对ssh开放并且与putty一起工作正常。如果您提供任何可以帮助我的想法,请感谢您。我无法手动为100个开关执行“show ver”命令。

3 个答案:

答案 0 :(得分:3)

正如上面提到的@dobbo,您必须在通道上执行invoke_shell(),以便您可以执行多个命令。此外,HP ProCurve在输出中包含ANSI转义代码,因此您必须将其删除。最后,HP ProCurve会抛出一个“按任意键继续”消息,至少在某些设备上必须通过该消息。

我在此库中有一个HP ProCurve处理程序https://github.com/ktbyers/netmiko

将device_type设置为“hp_procurve”。

Exscript也有一些ProCurve处理程序,虽然我没有足够的挖掘它以使它工作。

答案 1 :(得分:1)

我有使用ssh服务器连接到我的三星s4手机的相同经验。 我没有问题连接到SUSE VM或Rasperry Pi,也尝试过MobaXterm(上周putty是SO)。

我没有找到答案,但会分享我的研究。

我查看了源代码,并在channel.py中找到了第1122行(复制如下)。

使用我的手机(可能还有HP开关),我注意到根本没有登录信息或MOTD,当退出时(使用putty / mobaXterm),会话无法正常结束。

在其他一些阅读中,我发现参数不再得到作者的大力支持,但其他人正在努力将其移植到python 3x。

这是我找到的源代码。

def _wait_for_send_window(self, size):
    """
    (You are already holding the lock.)
    Wait for the send window to open up, and allocate up to C{size} bytes
    for transmission.  If no space opens up before the timeout, a timeout
    exception is raised.  Returns the number of bytes available to send
    (may be less than requested).
    """
    # you are already holding the lock
    if self.closed or self.eof_sent:
        return 0
    if self.out_window_size == 0:
        # should we block?
        if self.timeout == 0.0:
            raise socket.timeout()
        # loop here in case we get woken up but a different thread has filled the buffer
        timeout = self.timeout
        while self.out_window_size == 0:
            if self.closed or self.eof_sent:
                return 0
            then = time.time()
            self.out_buffer_cv.wait(timeout)
            if timeout != None:
                timeout -= time.time() - then
                if timeout <= 0.0:
                    raise socket.timeout()
    # we have some window to squeeze into

答案 2 :(得分:1)

似乎如果你不清理连接缓冲区,Paramiko在使用HP Procurves时会疯狂。首先你需要调用一个shell,或者Paramiko只是在第一个命令之后删除连接(正常行为,但令人困惑)。

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(switch_ip, username=switch_user, password=switch_pass,look_for_keys=False)
conn = ssh.invoke_shell()
recieveData() # <-- see below

实际处理数据非常重要,而且我已经了解到,您需要确保Paramiko实际上已经收到了所有数据,然后才会要求它执行此操作。我这样做是通过使用以下功能。您可以根据需要调整睡眠,在某些情况下,0.050可以正常工作。

def recieveData():
    tCheck = 0
    while not conn.recv_ready():
        time.sleep(1)
        tCheck+=1
        if tCheck >=10:
            print "time out"
    cleanThatStuffUp(conn.recv(1024)) # <-- see below

这是返回ssh客户端的垃圾示例。

[1;24r[24;1H[24;1H[2K[24;1H[?25h[24;1H[24;1HProCurve Switch 2650# [24;1H[24;23H[24;1H[?5h[24;23H[24;23Hconfigure[24;23H[?25h[24;32H[24;0HE[24;1H[24;32H[24;1H[2K[24;1H[?5h[24;1H[1;24r[24;1H[1;24r[24;1H[24;1H[2K[24;1H[?25h[24;1H[24;1H

还有退出代码在每个&#34; [&#34;之前]处理。所以为了解决这个问题,我想出了一些正则表达式来清理所有这些&#34;东西&#34;起来。

procurve_re1 = re.compile(r'(\[\d+[HKJ])|(\[\?\d+[hl])|(\[\d+)|(\;\d+\w?)')
procurve_re2 = re.compile(r'([E]\b)')
procurve_re3 = re.compile(ur'[\u001B]+') #remove stupid escapes

def cleanThatStuffUp(message):
   message = procurve_re1.sub("", message)
   message = procurve_re2.sub("", message)
   message = procurve_re3.sub("", message)
   print message

现在您可以继续输入命令,只需确保每次使用recieveData()清除缓冲区。

conn.send("\n") # Get past "Press any key"
recieveData()