-1

昨日、Paramiko に関して 2 行のコード変更を行いましたが、(私が知る限り) 悪影響を与えるべきではありませんでしたが、すぐに電話が鳴り始め、ユーザーがアクセスできないという報告が電子メールで届きました。 zfs ファイルシステムである NFS マウント ホーム ディレクトリ。私は同僚に意見を求めましたが、なぜこの変更が私がやろうとしていたことを達成できなかっただけでなく、なぜすべての人にすべてをホースでつなぐことになったのかについて、誰もが困惑しています.

Paramiko を使用して「zfs create」コマンドを実行し、新しいユーザーの NFS ホーム ディレクトリを作成した後、Python の「time.sleep(5)」行を使用して、リモート システムにコマンドを実行および処理する機会を与えていました (時々特に NFS サーバーに負荷がかかっている場合は、コマンドが実際に有効になるまでに 1 ~ 2 秒かかることがあります)。

結局のところ、5 秒の遅延では不十分なまれなケースに遭遇したようです。そこで、代わりに Python の「time.sleep(5)」関数から変更して、代わりに Paramiko の「channel.recv_exit_status()」関数を使用して終了ステータス コードを待機することにしました。が必要です (任意の秒数ではありません)。

コードの違いは次のとおりです(zfsパスとユーザー名の決定などのありふれたものを減らすために省略されています):

オリジナルバージョン:

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("homedirserver.example.com")

# Create zfs share
command = "zfs create {0}/{1}".format(zfs_parent, username)
ssh.exec_command(command)

time.sleep(5)

# Confirm creation (this can fail without a time.sleep delay above)
command = "zfs list -H {0}/{1}".format(zfs_parent, username)
stdin, stdout, stderr = ssh.exec_command(command)
error = stderr.read().strip()
if error != "":
    # log error, raise RuntimeError

新しいバージョン:

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("homedirserver.example.com")

# Create zfs share
command = "zfs create {0}/{1}".format(zfs_parent, username)
stdin, stdout, stderr = ssh.exec_command(command)  # <--- CHANGED
status = stdout.channel.recv_exit_status()          # <--- NEW

# Confirm creation
command = "zfs list -H {0}/{1}".format(zfs_parent, username)
stdin, stdout, stderr = ssh.exec_command(command)
error = stderr.read().strip()
if error != "":
    # log error, raise RuntimeError

これを行うと、「zfs create」コマンドがファイルサーバー上のプロセスとして存在し、完了しないようです。 ps -eaf | grep "zfs create"元の呼び出しプログラムから Ctrl+C で抜けるまで存在するファイル サーバー上のプロセスとしてコマンドを示します。最も驚くべきことは、そのサーバーからエクスポートされたすべての zfs ファイルシステムを完全に台無しにするのに十分であるように思われることです。Ctrl+C を押して数分待った後、すべてが通常どおりの状態に戻り、人々は NFS の停止を報告しなくなりました。

これはParamiko 1.14.1Python 2.7.8にあります。実行/呼び出しマシンはSolaris 11.2で、リモート ファイル サーバー (プロセスがハングする場所) はSolaris 11.1です。

4

1 に答える 1

1

より安全な方法でこれを実行してみましょう。

import pipes
command = "zfs create {0}/{1}".format(pipes.quote(zfs_parent), pipes.quote(username))
ssh.set_combine_stderr(True)
stdin, stdout, _ = ssh.exec_command(command)
stdin.close()
stdout_text = stdout.read()
status = stdout.channel.recv_exit_status()

違い:

  • stdin を明示的に閉じているため、プロセスが stdin をブロックすることはできません。
  • stderr を個別に維持したくないことを paramiko に伝えています。stderr コンテンツは、代わりに stdout にリダイレクトされます。(これにより、読み取りと書き込みの順序に関するいくつかのまれなケースが減少します。このコンテンツを追跡する必要があり、順序や長さの保証がない場合は、もっと興味深いものにする必要があります)。
  • また$(rm -rf /)pipes.quote().

もちろん、何が起こっているかを完全に確認するには、sysdig のようなものを使用して、操作中に ZFS サーバーで何が起こっているかを監視する必要があります (上記の仮説が正しければ、書き込み時にツールがブロックされていることがわかります)。ファイルシステムの可用性を中断するのに十分なカーネルと対話した後の stdout または stderr) ですが、テスト用の非実稼働環境がない場合、それを行うのは少し不快かもしれません。

于 2015-01-28T16:52:22.220 に答える