Why does paramiko sporadically raise an exception?

我只是一个虾纸丫 提交于 2020-06-26 07:15:27

问题


For convenience I have written a small wrapper class to login on a remote host, execute a command, end retrieve the data:

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

This code is adapted from the original paramiko python implementation. I just added the last 5 lines.

(FYI: MySSHCommandResult reads all data from stdout and strerr during construction and stores it for further use.)

The class MySSHClient is used within a simple python program:

....

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)

(Through these exit codes the python program tells the caller if everything succeeded. As you can see a variety of exit codes is used in order to allow a bit of error diagnosis on failure.)

So far so good. Basically this works. But what I do not understand is that sometimes my python program gives additional ouput like this:

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

Or like this:

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

Everything works fine all the time, but at about 10% to 20% of the time I see these error messages. Has anyone an idea why sometimes the cleanup fails on program termination? How can I avoid these error messages?


回答1:


For some reason, the garbage is not cleaned up automatically when sys.exit

To force the cleapup manually you can simply delete your allocated objected with del.

This is my code:

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)

Please mind the line:

del client, stdin_raw, stdout_raw, stderr_raw

This is my source: https://github.com/paramiko/paramiko/issues/1078#issuecomment-596771584




回答2:


I ran exactly into the same problem (did not find your question at first, opened mine, now deleted). If you do not exit with sys.exit, you should not see the error anymore. What I did in my case was wrap the calls to paramiko and such in a function, so that sys.exit is not called in the same scope. In your case you could do:

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)

And it should work !




回答3:


I have the same problem as you. I found that there was a '\n' at the end of my command string when I using exec_command(command). I delete the '\n' and it works. The exec_command can execute a series of commands if you use '\n' to separate it. So i think the last '\n' start a new object but it is none inside so cause that None Type error.



来源:https://stackoverflow.com/questions/37556888/why-does-paramiko-sporadically-raise-an-exception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!