8

Python の Paramiko モジュールを使用してリモート マシンに SSH で接続し、多数のファイル (14K 以上のファイルと 60 以上のデータ) を含むフォルダーを Tar/ZIP します。結果のzipは、それ自体で約10ギガです。これで、マシンから直接 zip/tar するコマンドを問題なく実行できます。ただし、同じコマンドをSSHClient.exec_commandで実行しようとすると、少し実行されますが、最終的にリモート マシンの圧縮プロセスがスリープ状態になります。そして、recv_exit_statusただ無期限にハングアップします。私が使用しているコードは次のとおりです。

stdin, stdout, stderr = ssh.exec_command('cd myDirectory; tar -zcvf output.tgz *')
status = stdout.channel.recv_exit_status()

Zipも使ってみました。

stdin, stdout, stderr = ssh.exec_command('cd myDirectory; find -name "*.gz" | zip output.zip -@')
status = stdout.channel.recv_exit_status()

どちらの場合も、コマンドをリモート マシンから直接実行すると、圧縮/TAR が完了します。結果ファイルは 9 GB のようです。しかし、Paramiko から試してみると、開始し、半分以上 (6 ギグ程度) 進み、プロセスがスリープ状態になります!

top を使用してリモート マシンのプロセスを監視しましたが、zip/tar は実行を開始しますが、終了する前に最終的にスリープ状態になります。そして、python スクリプトは無期限にハングアップします。

なぜこれが起こっているのですか?

4

3 に答える 3

2

タイムアウトに関連している可能性があります。timeout呼び出しに param (秒単位) を追加してみてください: exec_command(timeout=20*60)。これは 20 分の例です。詳細については、そのメソッドのドキュメント文字列を参照してください。

def exec_command(self, command, bufsize=-1, timeout=None, get_pty=False):
    """
    Execute a command on the SSH server.  A new `.Channel` is opened and
    the requested command is executed.  The command's input and output
    streams are returned as Python ``file``-like objects representing
    stdin, stdout, and stderr.

    :param str command: the command to execute
    :param int bufsize:
        interpreted the same way as by the built-in ``file()`` function in
        Python
    :param int timeout:
        set command's channel timeout. See `Channel.settimeout`.settimeout
    :return:
        the stdin, stdout, and stderr of the executing command, as a
        3-tuple

    :raises SSHException: if the server fails to execute the command
    """

また、私が経験した別の問題もあり、これも貢献する可能性があります: https://github.com/paramiko/paramiko/issues/109

https://github.com/paramiko/paramiko/issues/109#issuecomment-111621658で私の提案を試してください

stdout.channel.eof_received == 0が原因であるこの問題も経験しました

import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("1.1.1.1", username="root", password="pass")
stdin, stdout, stderr = client.exec_command("service XXX start")

stdin、stdout、および stderr は開いたままです...

>>> print stdin
<paramiko.ChannelFile from <paramiko.Channel 3 (open) window=2097152 in-buffer=50 -> <paramiko.Transport at 0x17eff90L (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>>
>>> print stdout
<paramiko.ChannelFile from <paramiko.Channel 3 (open) window=2097152 in-buffer=50 -> <paramiko.Transport at 0x17eff90L (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>>
>>> print stderr
<paramiko.ChannelFile from <paramiko.Channel 3 (open) window=2097152 in-buffer=50 -> <paramiko.Transport at 0x17eff90L (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>>

そのため、EOFは受信されませんでした...

>>> print stdin.channel.eof_received
0

通常、私は True を受け取り、stdout.read() だけで済みますが、安全のために次の回避策を使用します (うまくいきます!): タイムアウトを待ち、stdout.channel.close() を強制してから stdout.read():

>>> timeout = 30
>>> import time
>>> endtime = time.time() + timeout
>>> while not stdout.channel.eof_received:
...     sleep(1)
...     if time.time() > endtime:
...         stdout.channel.close()
...         break
>>> stdout.read()
'Starting XXX: \n[  OK  ]\rProgram started . . .\n'
>>>
于 2016-04-20T07:26:59.340 に答える