问题
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