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