为什么paramiko偶尔提出例外?

时间:2016-05-31 22:47:15

标签: python ssh paramiko

为方便起见,我编写了一个小包装类来登录远程主机,执行命令,结束检索数据:

def MySSHClient:

    def connect(self, remoteHost, remotePort, userName, password):
        self.__s = paramiko.SSHClient()
        self.__s.load_system_host_keys()
        self.__s.connect(remoteHost, remotePort, userName, password)

    def exec_command(self, command):
        bufsize = -1
        chan = self.__s.get_transport().open_session()
        chan.exec_command(command)
        stdin = chan.makefile('wb', bufsize)
        stdout = chan.makefile('r', bufsize)
        stderr = chan.makefile_stderr('r', bufsize)
        stdin.close()
        exitcode = chan.recv_exit_status()
        r = MySSHCommandResult(command, stdin, stdout, stderr, exitcode)
        chan.close()
        return r

    def close(self):
        self.__s.close()

此代码改编自原始的paramiko python实现。我刚刚添加了最后5行。

(仅供参考:MySSHCommandResult在构建期间从stdout和strerr读取所有数据,并将其存储以供进一步使用。)

MySSHClient类在一个简单的python程序中使用:

....

exitCode = 0
s = None
try:
    ....
    exitCode = 3
    s = MySSHClient()
    s.connect(host, port, login, password)
    exitCode = 4
    result = s.exec_command(myCommand)
    exitCode = 5
    if not result.isSuccess():
        raise Exception("Failed to execute command!")
    result.dump()    # for current debugging purposes
    exitCode = 0
except:
    pass

if s is not None:
    s.close()
sys.exit(exitCode)

(通过这些退出代码,python程序告诉调用者是否一切都成功。正如您所看到的那样,使用了各种退出代码,以便在失败时进行一些错误诊断。)

到目前为止一切顺利。基本上这是有效的。但我不明白的是,有时我的python程序会提供额外的输出:

Exception ignored in: <bound method BufferedFile.__del__ of <paramiko.ChannelFile from <paramiko.Channel 0 (closed) ->     <paramiko.Transport at 0x74300588 (unconnected)>>>>
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/paramiko/file.py", line 61, in __del__
  File "/usr/local/lib/python3.5/dist-packages/paramiko/file.py", line 79, in close
  File "/usr/local/lib/python3.5/dist-packages/paramiko/file.py", line 88, in flush
TypeError: 'NoneType' object is not callable

或者像这样:

Exception ignored in: <object repr() failed>
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/paramiko/file.py", line 61, in __del__
  File "/usr/local/lib/python3.5/dist-packages/paramiko/file.py", line 79, in close
  File "/usr/local/lib/python3.5/dist-packages/paramiko/file.py", line 88, in flush
TypeError: 'NoneType' object is not callable

一切正常,但在大约10%到20%的时间我看到这些错误消息。有谁知道为什么有时清理会在程序终止时失败?如何避免这些错误消息?

3 个答案:

答案 0 :(得分:6)

由于某种原因,sys.exit时不会自动清除垃圾

要手动强制分裂,您可以简单地使用 del 删除分配的对象。

这是我的代码:

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(host, port, username, password)
stdin_raw, stdout_raw, stderr_raw = client.exec_command(cmd)
exit_code = stdout_raw.channel.recv_exit_status() 

stdout = []
for line in stdout_raw:
    stdout.append(line.strip())

stderr = []
for line in stderr_raw:
    stderr.append(line.strip())


# Clean up elements
client.close()
del client, stdin_raw, stdout_raw, stderr_raw


logger.debug("stdout: %s" % stdout)
logger.debug("stderr: %s" % stderr)
logger.debug("exit_code: %s" % exit_code)

请注意以下一行:

del client, stdin_raw, stdout_raw, stderr_raw

这是我的出处: https://github.com/paramiko/paramiko/issues/1078#issuecomment-596771584

答案 1 :(得分:1)

我和你有同样的问题。我发现使用'\n'时命令字符串的末尾有一个exec_command(command)。我删除了'\n',它起作用了。如果使用exec_command'\n'分开,则可以执行一系列命令。所以我认为最后一个'\n'开始一个新对象,但是里面没有,所以导致None Type错误。

答案 2 :(得分:0)

我遇到了同样的问题(一开始没找到你的问题,打开我的,现在已删除)。如果您不退出sys.exit,则不应再看到错误。我在我的案例中所做的是将调用包装在函数中,这样就不会在同一范围内调用sys.exit。在你的情况下,你可以这样做:

def my_func(host, port, login, password, myCommand)
    exitCode = 0
    s = None
    try:
        ....
        exitCode = 3
        s = MySSHClient()
        s.connect(host, port, login, password)
        exitCode = 4
        result = s.exec_command(myCommand)
        exitCode = 5
        if not result.isSuccess():
            raise Exception("Failed to execute command!")
        exitCode = 0
    except:
        pass
    if s is not None:
        s.close()
    return exitCode

exit_code = my_func(my_host, my_port, my_login, my_password, my_command)
sys.exit(exit_code)

它应该有效!