Python : Paramiko - channel.exec_command 不间歇性地返回输出

Python : Paramiko - channel.exec_command not returning output intermittently

我在使用 Paramiko 执行远程操作时遇到间歇性问题。

if channel.active:
    contents = io.StringIO()
    error = io.StringIO()
    try:
        LOG.info('{} - Executing script {}  - as {} user '.format(self.target_host, script, self.targetvmuser))
        channel.exec_command(script)
        while not channel.exit_status_ready():
            if channel.recv_ready():
                data = channel.recv(1024)
                LOG.debug(data.decode())
                while data:
                    contents.write(data.decode())
                    data = channel.recv(1024)
                    LOG.debug(data.decode())
            if channel.recv_stderr_ready():
                error_buff = channel.recv_stderr(1024)
                LOG.debug(error_buff.decode())
                while error_buff:
                    error.write(error_buff.decode())
                    error_buff = channel.recv_stderr(1024)
                    LOG.debug(error_buff.decode())
        exit_status = channel.recv_exit_status()

下面是2次执行的调试日志。我无法弄清楚为什么下面的输出在一个 VM 上返回,而在另一个 VM 上却没有。

2022-03-17 12:14:42 [DEBUG] - -rw-rw-r--. 1  test test 1702 Mar 17 12:14 /tmp/testfile
2022-03-17 12:14:42 [DEBUG] -

Linux 带有 Paramiko 2.7.2 的虚拟机 - 间歇性错误 运行。

2022-03-17 12:14:20 [DEBUG][chan 0] Max packet out: 32768 bytes
2022-03-17 12:14:20 [DEBUG] - Secsh channel 0 opened.
2022-03-17 12:14:20 [DEBUG] - [chan 1] Max packet in: 32768 bytes
2022-03-17 12:14:20 [DEBUG] - [chan 1] Max packet out: 32768 bytes
2022-03-17 12:14:20 [DEBUG] - Secsh channel 1 opened.
2022-03-17 12:14:20 [DEBUG] - [chan 1] Sesch channel 1 request ok
2022-03-17 12:14:20 [INFO ] - [chan 1] Opened sftp connection (server version 3)
2022-03-17 12:14:20 [DEBUG] - [chan 1] open(b'/tmp/testfile', 'wb')
2022-03-17 12:14:20 [DEBUG] - Sending global request "keepalive@lag.net"
2022-03-17 12:14:20 [DEBUG] - [chan 1] open(b'/tmp/testfile', 'wb') -> 00000000
2022-03-17 12:14:20 [DEBUG] - [chan 1] close(00000000)
2022-03-17 12:14:20 [DEBUG] - [chan 1] stat(b'/tmp/testfile')
2022-03-17 12:14:20 [DEBUG] - [chan 2] Max packet in: 32768 bytes
2022-03-17 12:14:20 [DEBUG] - [chan 2] Max packet out: 32768 bytes
2022-03-17 12:14:20 [DEBUG] - Secsh channel 2 opened.
2022-03-17 12:14:20 [INFO ] - 10.9.59.11 - Executing script ls -ltr /tmp/testfile  - as opc user 
2022-03-17 12:14:20 [DEBUG] - [chan 2] Sesch channel 2 request ok
2022-03-17 12:14:20 [DEBUG] - Sending global request "keepalive@lag.net"
2022-03-17 12:14:20 [DEBUG] - Sending global request "keepalive@lag.net"
2022-03-17 12:14:20 [DEBUG] - [chan 2] EOF received (2)
2022-03-17 12:14:20 [DEBUG] - [chan 2] EOF sent (2)
2022-03-17 12:14:20 [INFO ] - 10.9.59.11 -script ls -ltr /tmp/testfile 0 - exit code is 0
2022-03-17 12:14:20 [INFO ] - [chan 1] sftp session closed.
2022-03-17 12:14:20 [DEBUG] - [chan 1] EOF sent (1)
2022-03-17 12:14:20 [DEBUG] - [chan 0] EOF sent (0)
2022-03-17 12:14:20 [DEBUG] - [chan 0] EOF sent (0)
2022-03-17 12:14:20 [DEBUG] - EOF in transport thread

Linux VM with Paramiko 2.9.2 & Windows – Paramiko 2.7.2 – 没有问题 – 总是好的 运行.

2022-03-17 12:14:42 [DEBUG] - [chan 0] Max packet out: 32768 bytes
2022-03-17 12:14:42 [DEBUG] - Secsh channel 0 opened.
2022-03-17 12:14:42 [DEBUG] - [chan 1] Max packet in: 32768 bytes
2022-03-17 12:14:42 [DEBUG] - [chan 1] Max packet out: 32768 bytes
2022-03-17 12:14:42 [DEBUG] - Secsh channel 1 opened.
2022-03-17 12:14:42 [DEBUG] - [chan 1] Sesch channel 1 request ok
2022-03-17 12:14:42 [DEBUG] - Sending global request "keepalive@lag.net"
2022-03-17 12:14:42 [INFO ] - [chan 1] Opened sftp connection (server version 3)
2022-03-17 12:14:42 [DEBUG] - [chan 1] open(b'/tmp/testfile', 'wb')
2022-03-17 12:14:42 [DEBUG] - [chan 1] open(b'/tmp/testfile', 'wb') -> 00000000
2022-03-17 12:14:42 [DEBUG] - [chan 1] close(00000000)
2022-03-17 12:14:42 [DEBUG] - Sending global request "keepalive@lag.net"
2022-03-17 12:14:42 [DEBUG] - [chan 1] stat(b'/tmp/testfile')
2022-03-17 12:14:42 [DEBUG] - [chan 2] Max packet in: 32768 bytes
2022-03-17 12:14:42 [DEBUG] - Sending global request "keepalive@lag.net"
2022-03-17 12:14:42 [DEBUG] - [chan 2] Max packet out: 32768 bytes
2022-03-17 12:14:42 [DEBUG] - Secsh channel 2 opened.
2022-03-17 12:14:42 [INFO ] - 10.9.59.11 - Executing script ls -ltr /tmp/testfile  - as test user 
2022-03-17 12:14:42 [DEBUG] - Sending global request "keepalive@lag.net"
2022-03-17 12:14:42 [DEBUG] - [chan 2] Sesch channel 2 request ok
2022-03-17 12:14:42 [DEBUG] - [chan 2] EOF received (2)
2022-03-17 12:14:42 [DEBUG] - [chan 2] EOF sent (2)
2022-03-17 12:14:42 [DEBUG] - -rw-rw-r--. 1  test test 1702 Mar 17 12:14 /tmp/testfile
2022-03-17 12:14:42 [DEBUG] - 
2022-03-17 12:14:42 [INFO ] - 10.9.59.11 -script ls -ltr /tmp/testfile 0 - exit code is 0
2022-03-17 12:14:42 [INFO ] - [chan 1] sftp session closed.
2022-03-17 12:14:42 [DEBUG] - [chan 1] EOF sent (1)
2022-03-17 12:14:42 [DEBUG] - [chan 0] EOF sent (0)
2022-03-17 12:14:42 [DEBUG] - [chan 0] EOF sent (0)
2022-03-17 12:14:42 [DEBUG] - EOF in transport thread

这可能是竞争条件。如果命令已完成,exit_status_ready 可以 return 为真,即使您还没有阅读它的完整输出。

正确的代码如下:

while True:
    exited = channel.exit_status_ready()
    if channel.recv_ready():
        data = channel.recv(1024)
        LOG.debug(data.decode())
        while data:
            contents.write(data.decode())
            data = channel.recv(1024)
            LOG.debug(data.decode())
    if channel.recv_stderr_ready():
        error_buff = channel.recv_stderr(1024)
        LOG.debug(error_buff.decode())
        while error_buff:
            error.write(error_buff.decode())
            error_buff = channel.recv_stderr(1024)
            LOG.debug(error_buff.decode())
    if exited:
        break