web-dev-qa-db-ja.com

SSHが原因でwhileループが停止する

ようやく、数週間苦労してきた問題をなんとか解消することができました。 「承認済みキー」を使用してSSHを使用し、コマンドをリモートで実行します。 whileループで実行する場合を除いて、すべて問題ありません。ループは、sshコマンドで反復を完了すると終了します。

長い間、これはある種のkshの奇妙さだと思っていましたが、bashが実際には同じように動作することを発見しました。

問題を再現する小さなサンプルプログラム。これは、スナップショットを取得してクラスター内のノード間でそれらを複製する大規模な実装から抽出されます。

#!/bin/bash

set -x

IDTAG=".*zone"
MARKER="mark-$(date +%Y.%m.%d.%H.%M.%S)"
REMOTE_Host=sol10-target
ZFSPARENT=rpool

ssh $REMOTE_Host zfs list -t filesystem -rHo name,mounted $ZFSPARENT | grep "/$IDTAG    " > /tmp/actionlist

#for RMT_FILESYSTEM in $(cat /tmp/actionlist)
cat /tmp/actionlist | while read RMT_FILESYSTEM ISMOUNTED
do
   echo ${RMT_FILESYSTEM}@${MARKER}
   [ "$ISMOUNTED" = "yes" ] && ssh $REMOTE_Host zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER}
   echo Remote Command Return Code: $?
done

(zfs listの「-H」オプションの動作の定義に従って、grep検索式にタブ文字があることに注意してください。)

私のサンプルには、すべての「ゾーン」が次のような名前のデータセットにルートファイルシステムを持つルート用のZFSファイルシステムがいくつかあります

POOL/zones/app1zone
POOL/zones/group2/app2zone

等.

上記のループは、選択されたデータセットごとにスナップショットを作成するはずですが、代わりに最初のデータセットのみを操作して終了します。

プログラムが正しい数のデータセットを見つけたことは、スクリプトが存在した後に「/ tmp/actionlist」ファイルを確認することで簡単に確認できます。

たとえば、sshコマンドがechoコマンドに置き換えられた場合、ループはすべての入力行を反復します。または私のお気に入り-問題のコマンドに「エコー」を追加します。

Forループを代わりに使用した場合も機能しますが、データセットのリストの潜在的なサイズが原因で、拡張されたコマンドラインの最大長で問題が発生する可能性があります。

私は99.999%で、sshコマンドを含むループだけが問題を起こすと確信しています!

Sshコマンドが実行される反復が完了することに注意してください!それはまるでwhileループに入れられたデータが突然失われたかのようです...最初のいくつかの入力行がsshコマンドを実行しない場合、ループは実際にSSHコマンドを実行するまで続きます。

私がこれをテストしている私のラップトップでは、2つまたは3つのサンプルデータセットのみを備えた2つのSolaris 10 VMを持っていますが、大規模なSPARCシステムが稼働する予定の場合)でも同じことが起こります。そして、多くのデータセットがあります。

30
Johan

SSHが標準入力から読み取って、アクションリストを使い果たしている可能性があります。 sshの標準入力を/ dev/nullにリダイレクトしてみます。

ssh $REMOTE_Host zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER} </dev/null

一般的なルールとして、while readスタイルのループで標準入力に干渉する可能性のあるコマンドを実行するときは、ループ本体全体を中括弧で囲みます。

cat /tmp/uuoc | while read RMT_FILESYSTEM ISMOUNTED
do {
    echo ${RMT_FILESYSTEM}@${MARKER}
    [ "$ISMOUNTED" = "yes" ] && ssh $REMOTE_Host zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER}
    echo Remote Command Return Code: $?
} < /dev/null; done
45
BatchyX