私はついに、数週間苦労してきた問題を解決することができました。 「許可されたキー」で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リストの「-H」オプションの動作の定義に従って、grep検索式にTAB文字があることに注意してください。)
私のサンプルには、ルート用のZFSファイルシステムがいくつかあり、すべての「ゾーン」には、次のような名前のデータセット上のルートファイルシステムがあります
POOL / zones / app1zone
POOL / zones / group2 / app2zone
など
上記のループは、選択した各データセットのスナップショットを作成する必要がありますが、代わりに最初のデータセットでのみ動作し、その後終了します。
プログラムが適切な数のデータセットを検出したことは、スクリプトの存在後に「/ tmp/actionlist」ファイルをチェックすることで簡単に確認できます。
sshコマンドがechoコマンドなどに置き換えられた場合、ループはすべての入力行を繰り返します。または私のお気に入り–問題のあるコマンドの前に「echo」を追加します。
代わりにforループを使用すると、それも機能しますが、データセットのリストの潜在的なサイズが原因で、拡張されたコマンドラインの最大長で問題が発生する可能性があります。
私は今、99.999%の確率で、sshコマンドを含むループだけが問題を引き起こします!
sshコマンドが実行される反復が完了することに注意してください! whileループに組み込まれたデータが突然失われたかのようです…最初の数行の入力がsshコマンドを実行しない場合、実際にSSHコマンドを実行するまでループが続きます。
これをテストしている私のラップトップには、サンプルデータセットが約2つまたは3つしかない2つのSolaris 10 VMがありますが、これが稼働することを意図した大規模なSPARCシステムでも同じことが起こり、多くのデータセットがあります。
> 関連:cronシェルを変更する方法(shからbash)?承認された回答:
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