Skip to Content
IoT アプリ開発IronFlock CLISSH 経由のリモートマシン

SSH 経由のリモートマシン

--host は、ironflock コマンドを、このマシンではなく SSH 経由で別のマシン上で実行します。Mac を含むラップトップから、デバイスに ironflock をインストールせずにデバイスを管理するのに使います。複数回指定するか、ホスト一覧ファイルと組み合わせると、多数のマシンで同時にコマンドを実行します。

ironflock --host [user@]machine <command> [flags] ironflock --host [user@]machine --host [user@]machine ... <command> [flags] ironflock --hosts <file> [--parallel <n>] <command> [flags]

completion 以外のすべてのコマンドが、この方法で別のマシン上で実行されます。--host、--hosts、--parallel は グローバルフラグ で、コマンド名の前にも後にも置けます。

1 台のマシン

--host [user@]machine は、同じコマンドを同じフラグでそのマシン上で実行します。コマンドの出力はそのまま返され、stdout は stdout に、stderr は stderr に出力されます。終了コードも同様に返されます。

$ ironflock --host pi@device-17 version ironflock 2.0.2 linux/arm64 $ ironflock --host pi@device-17 agent remove --yes --json 2>/dev/null {"action":"removed","removed":[...]}

別のマシンに必要なもの

  • amd64、arm64、または 32 ビット ARM(v5〜v7)の Linux。 それ以外のシステムでは、終了コード 3 で終了します。
  • コマンドを実行する SSH サーバー。 scp や SFTP は必要ありません。
  • POSIX のログインシェル: sh、bash、dash、zsh。csh、tcsh、fish では、その旨のメッセージを出して終了コード 3 で終了します。
  • root でのログイン、または sudo。 root が必要なコマンドに必要です(別のマシンでの root を参照)。

マシンに ironflock をインストールしておく必要はありません。実行のたびに、自身のバイナリを持ち込みます。

SSH の設定

--host はこのマシンの ssh を使うため、~/.ssh/config、鍵、SSH エージェント、踏み台ホストは ssh と同じように機能します。コマンドに不要なもの、つまりエージェント転送と X11 転送、ポート転送、RemoteCommand、LocalCommand は無効にします。

--host が受け付けるのは [user@]machine だけです。ポートやその他のオプションは ~/.ssh/config に記載します:

Host device-* User pi Port 2222 StrictHostKeyChecking accept-new

この設定により、ironflock --host device-17 status はポート 2222 で pi としてログインし、ssh はまだ知らないデバイスのホスト鍵を受け入れます。- で始まる --host の値は拒否されます。英字、数字、.、_、-、IPv6 アドレスの : と % 以外の文字を含む値も拒否されます。

制御ソケットのパスが十分に短い場合は、1 つの SSH 接続が実行全体で使われます。ソケットは一時フォルダーの下に、それができなければ /tmp の下に作成されます。この場合、ssh がパスワードを尋ねるのは 1 回だけです。そうでない場合は、実行の各手順がそれぞれ接続を開き、ssh はそのたびにパスワードを尋ねます。

ironflock agent install または IronFlockOS がセットアップしたデバイスには、プロジェクトオーナー用の SSH ユーザーがあり、デバイスの .flock ファイルに含まれる鍵でログインします。ユーザー名と、ファイルから鍵を取り出す方法は SSHアクセス に記載しています。

マシン上で行われること

  1. バイナリ。 プラットフォームが同じ場合、マシンには、ここで実行中のバイナリが送られます。そうでない場合、ironflock はマシンのプラットフォーム用のバイナリを <download base>/cli/<os>/<arch>/<version>/ironflock からダウンロードし、使う前にここで検証します。検証するのは、このバイナリに含まれる IronFlock のリリース鍵による署名(.asc)と、ビルド情報です。ビルド情報には、プログラム名 ironflock、マシンのプラットフォーム、このバイナリと同じソースリビジョンが記載されている必要があります。ダウンロードしたファイルはキャッシュフォルダー(Linux では ~/.cache/ironflock、Mac では ~/Library/Caches/ironflock)に保存され、使うたびに再度検証されます。
  2. フォルダー。 バイナリは、ログインユーザーだけが読める新しいフォルダー(mktemp -d)に置かれます。フォルダーはマシンの ${TMPDIR:-/tmp} の下に作成され、一時フォルダーでプログラムを実行できない場合(noexec でマウントされたファイルシステム)は、ログインユーザーのホームディレクトリの下に作成されます。どちらでも実行できない場合、コマンドは終了コード 3 で終了し、両方の場所を示します。フォルダーから何かを実行する前に、マシンは、フォルダーとバイナリがログインユーザーの所有でシンボリックリンクではないこと、バイナリが想定どおりのバージョンとプラットフォームであることを確認します。
  3. ファイル。 コマンドのフラグで指定したファイルが一緒に送られます(フラグで指定するファイル を参照)。
  4. コマンド。 ログインユーザーとして、または sudo を通して実行されます(別のマシンでの root を参照)。
  5. 後片付け。 コマンドが終了すると、マシンはバイナリとコピーを含むフォルダーを削除します。失敗した後、接続が切れた後、シグナル HUP、INT、QUIT、TERM、PIPE、USR1、USR2 を受けた後も同様です。

--host は、agent install の後でも、マシンに ironflock を残しません。以降も --host を使い続けるか、インストール用の 1 行 でマシンに ironflock をインストールしてください。引数なしの場合、この 1 行はインストールだけを行います。--host での self-update は、実行用のバイナリではなく、マシンの /usr/local/bin/ironflock を更新します(ironflock self-update)。

次の 2 つの場合、フォルダー ironflock.* がマシンに残ります:

  • コマンドの実行中に、マシンで停電や kill -9 が起きた場合。フォルダーにはバイナリとコピーが含まれます。
  • コピーの後、コマンドの開始前に接続が切れた場合、またはコマンドを開始する手順が接続している間に、ここで実行が中断された場合。フォルダーにはバイナリが含まれ、端末でコマンドを実行した場合はコピーも含まれます。

.flock ファイルのコピーにはデバイスのシークレットが、パスフレーズファイルのコピーには WiFi のパスフレーズが、パスワードファイルのコピーにはプロキシのパスワードが含まれます。これらを読めるのはログインユーザーと root だけです。このようなフォルダーは手動で削除してください。

フラグで指定するファイル

フラグコマンド
-c, --config(.flock ファイル)agent install、agent configure、doctor、os flash、os install、os reset
--wifi-password-fileos flash
--proxy-password-fileagent install、agent configure、os install

各ファイルはここで読み取られ、相対パスはこのマシンの作業フォルダーを基準にします。パスフレーズファイルとパスワードファイルにはパイプ(/dev/stdin)も使え、1 回だけ読み取られます。内容は、SSH 接続の標準入力でマシンに送られます。ファイルもそのサイズも、ここでもマシン上でもコマンドラインには載りません。マシン上では、すべてのユーザーがコマンドラインを読めるためです。マシンは、各サイズをコマンドが受け付ける上限と照合し、その後、すべてが届いたことを確認します。

マシン上のコピーは <folder>/1/device.flock です。実行用フォルダーの中にある専用のフォルダー(モード 0700)に、ここでの名前のまま、モード 0600 で置かれます。そこでのコマンドにはこのパスが渡されるため(例:--config=/tmp/ironflock.k3Xf9QpL2m/1/device.flock)、ファイルの内容に関するエラーはコピーを示します。

次の場合、コマンドはこのマシンで終了します:

  • 終了コード 1 — 通常のファイルでないファイル(パスフレーズファイルとパスワードファイルはパイプでもかまいません)、またはコマンドが受け付けるより大きいファイル。上限は、.flock ファイルが 5 MiB、パスフレーズファイルとパスワードファイルが 4096 バイトです。
  • 終了コード 2 — 制御文字を含むファイル名。
  • 終了コード 2 — os flash の --image-file と --output。--host はマシンにイメージをコピーせず、ファイルを持ち帰ることもしません。このコマンドは --host を付けずにここで実行するか、マシン自体で実行してください。--image-file を付けなければ、マシンが自分でイメージをダウンロードします。

別のマシンでの root

  • root が必要なコマンドは、ログインユーザーが root でない場合、sudo を通して実行されます。パスワードも端末も必要としない sudo であれば、どこでも動作します。
  • version、os images、os drives は、ログインユーザーとして実行されます。
  • status と doctor は、root で実行するとより多くを読み取ります。ログインユーザーが root の場合、またはパスワードも端末も必要とせずに sudo を使える場合は、root で実行されます。そうでない場合は、質問せずにログインユーザーとして実行され、ヒントに --host root@machine を付けたコマンドが示されます。
  • agent logs は root のファイルを読むため、sudo を通して実行されます。
  • sudo がパスワードを尋ねる場合、またはその設定が端末を求める場合(requiretty)、マシン上に端末が必要です。そのためには、ここで stdin、stdout、stderr のすべてが端末である必要があります。そうでない場合、コマンドは何もコピーする前に終了コード 3 で終了します。その場合は、root でログインするか、ログインユーザーがパスワードも端末も必要とせずに sudo を使えるようにするか、リダイレクトせずに端末でコマンドを実行してください。
  • コマンドを実行する直前に sudo が拒否した場合も、終了コード 3 で終了します。

そこでのコマンドが次に実行するよう示すコマンドは、こちら側で実行するコマンドとして、sudo を付けずに示されます。--host が自分で root を取得するためです:ironflock --host pi@device-17 agent start。

端末、質問、出力

  • ここに端末がある場合、マシン上のコマンドにも端末が割り当てられるため、コマンドは質問できます。その場合、stdout と stderr はまとめて端末に返されます。
  • ここに端末がない場合(パイプ、--json の出力をプログラムに渡す場合、CI)、stdout と stderr は分かれたままで、コマンドは何も質問しません。--yes で確定します。マシン上のログインユーザーのファイルが出力するもの(たとえば echo する .bashrc)は stdout から取り除かれるため、stdout にはコマンドの結果だけが出力されます。
  • --yes、--json、コマンドのフラグは一緒に渡されます。ダウンロードベースは --download-base として渡されます。値は、フラグ、またはこのマシンの IRONFLOCK_DL_BASE です。ログイン情報を含むダウンロードベース(https://user:[email protected]/dl)を指定すると、どのマシンにも接続する前に終了コード 2 で終了します。マシン上では、そこのすべてのユーザーが読めるコマンドラインに載ってしまうためです。
  • --help、help、コマンドを付けないグループ、completion には、ここで応答します。これらの出力は、どのマシンでも同じだからです。
  • コマンドの実行前にマシンが stdout に送るもの(マシンの応答と、ログインユーザーのファイルが出力するテキスト)は、64 KiB まで読み取られます。それを超えると、そこでコマンドを実行する前に、終了コード 1 で実行を終了します。

Ctrl-C と接続の切断

ここでの Ctrl-C は、そこでのコマンドに、その端末で Ctrl-C を押したのと同じように届きます。接続が切れると、それはハングアップとしてコマンドに届きます。ここに端末があってもなくても同じです。Ctrl-C の後、--host は、そこでのコマンドが終了したことを終了コード(Ctrl-C で終了した場合は 130)とともにマシンが伝えてくるまで、最大 15 秒待ちます。マシンが時間内に伝えてこない場合、または先に接続が切れた場合、--host は 130 で終了し、コマンドがまだそこで実行されている可能性があることを示します。Ctrl-C を受けた時点でコマンドがまだ開始していなかった実行では、コマンドは開始されません。

--host での os install には独自のルールがあります。質問に回答した後は、接続が切れても止まらず、コマンドはマシンが IronFlockOS として戻ってくるのをここで待ちます。ironflock os install を参照してください。

終了コードとエラー

終了コードはコマンドのものです(終了コード)。--host は次の終了コードを追加します:

コード意味
255ssh が失敗した:接続できない、ログインまたはホスト鍵が拒否された、接続が切れた
3マシンがコマンドを実行できない:別のシステムまたは CPU、POSIX シェルではないログインシェル、プログラムを実行できるフォルダーがない、ログインユーザーに許可を与えない sudo
130割り込み。ここでの割り込み(Ctrl-C)、またはマシン上のコマンドへの割り込み(そこでのハングアップ、割り込み、終了シグナル)

--host 自体の失敗は、ほかのエラーと同じ扱いです。stderr に Error: の行が出力されるか、--json では stdout にエラーオブジェクトが出力されます。唯一の例外として、コマンドの出力がすでに届いていた場合は、その出力が結果となり、エラーは stderr の Error: の行だけになります。--json でも同じです。

複数のマシン

--host を複数回指定するか --hosts <file> を指定すると、--host が 1 台のマシンでコマンドを実行するのと同じように、各マシンでコマンドを実行します。--host のマシンが先で、その後にファイルのマシンが続きます。マシンが 1 台だけのホスト一覧ファイルも、複数のマシンと同じように実行されます。

$ ironflock --host pi@vm1 --host pi@vm2 --host pi@vm3 status pi@vm2: Agent: installed in /opt/ironflock/device-agent pi@vm2: Version: 1.6.9 pi@vm2: Service: running (ironflock-device-agent.service) pi@vm3: ssh: connect to host vm3 port 22: Connection timed out pi@vm3: Error: the SSH connection to pi@vm3 failed pi@vm1: Agent: installed in /opt/ironflock/device-agent ... Summary of "status" on 3 machines, exit code 255: 2 done, 1 ssh. pi@vm1 done pi@vm2 done pi@vm3 255 ssh: the SSH connection to pi@vm3 failed (ssh: connect to host vm3 port 22: Connection timed out)

ホスト一覧ファイル

ファイルには、1 行に 1 つの [user@]machine を記載します。# はコメントの開始で、行末まで続きます。空行は無視されます。ファイルには --hosts <(...) のようなパイプも使え、サイズは最大 1 MiB です。

# 包装ライン 3 pi@device-17 pi@device-18 pi@device-19 # the spare unit
# ファイル内のすべてのマシンの状態を、20 台ずつ表示する ironflock --hosts line3.txt --parallel 20 status # ファイル内のすべてのマシンでエージェントを更新する。agent update は質問するため、--yes が必要 ironflock --hosts line3.txt agent update --yes # 拠点のデバイスに 1 つのプロキシアカウントを設定する。パスワードはファイルから渡す ironflock --hosts site-a.txt agent configure --https-proxy http://[email protected]:3128 --proxy-password-file proxy-password.txt --yes

次の場合は、何かを実行する前に終了コード 2 で終了し、エラーにはファイルと行が示されます:

  • 複数の語を含む行
  • --host が拒否するマシン
  • 2 回記載されたマシン。同じマシンを 2 つの異なるユーザーで記載した場合も 2 回とみなします。コマンドがそのマシンで同時に 2 回実行されることになるためです。1 台のマシンのアドレスと名前は、同じマシンとは認識されません。

並列実行

同時に実行されるマシンは最大 --parallel 台です。フラグがない場合は 10 台で、範囲は 1〜100 です。マシンは指定された順に開始し、1 台が終了すると次の 1 台が開始します。複数のマシンがないのに --parallel を指定すると、終了コード 2 で終了します。

質問しない SSH

どのマシンにも端末は割り当てられず、ssh は何も尋ねません(BatchMode=yes)。次の場合は、そのマシンで ssh 自身のメッセージとともに終了コード 255 で失敗し、ほかのマシンは実行を続けます:

  • パスワードを求めるログイン
  • パスフレーズを SSH エージェントが保持していない鍵
  • ssh がまだ知らないホスト鍵

新しいホスト鍵を受け入れるには、一度 ssh で接続するか、上の例 のように、~/.ssh/config でそれらのマシンに StrictHostKeyChecking accept-new を設定してください。ssh は 30 秒で接続をあきらめるため(~/.ssh/config の設定にかかわらず ConnectTimeout=30)、電源の切れたマシンはその時点で報告されます。そこで sudo がパスワードまたは端末を求める場合は、そのマシンで終了コード 3 で終了します。その場合、status と doctor はログインユーザーとして実行されます。

複数のマシンの出力

  • マシンが出力する各行は、先頭に <host>: を付けて、行単位で届きます。stdout は stdout に、stderr は stderr に出力されます。マシンの行は、届いた順に混ざります。
  • 改行のない最後の行には改行が付けられます。64 KiB を超える行は 64 KiB ずつに分けて届き、それぞれの先頭にホストが付きます。
  • タブ以外の制御文字は、行の中でもサマリーの中でもエスケープされて届きます(\x1b、\r)。そのため、どのマシンもカーソルを動かしたり、ほかのマシンの行を上書きしたりできません。行末のキャリッジリターンは取り除かれます。
  • ここで失敗した実行は、--host が 1 台のマシンについて出力するのと同じように、先頭にホストを付けた Error: の行を追加します。
  • 最後に、stderr にサマリーが出力されます。終了コードと、どのように終了したマシンが何台あるか、続いて指定された順にマシンごとに 1 行です。各行は done、または終了コードとその種類と理由を示します。理由は、ここでのエラー(255 の場合は ssh 自身のメッセージ)か、コマンドの Error: の行です。Ctrl-C の後にコマンドの終了を確認できなかったマシンは interrupted, may still run です。

複数のマシンの終了コード

コマンドは、マシンの中で最も悪い終了コードで終了します。すべてのマシンが 0 で終了した場合は 0 です。それ以外の場合は、最も悪いものから順に次のとおりです:

  1. 130 — ここ、またはマシン上で中断された。
  2. 1 — マシン上でコマンドが失敗した。そこでどのコードで終了したかにかかわらず、マシンが中途半端に変更されたままの可能性があります。
  3. 255 — マシンに到達できなかった、または接続が切れた。
  4. 3 — マシンがコマンドに必要な状態になかった、またはコマンドを実行できない。
  5. 4 — 質問への回答が「いいえ」だった。

終了コード 2 は、すべてのコマンドと同じく、ここでのコマンドラインの誤りです。

JSON Lines 出力

--json を付けると、stdout には、各マシンのコマンドが終了するたびに終了した順でマシンごとに 1 行が出力され、それ以外は何も出力されません。プログラムは、届いた行から順に読み取れます。

{"host":"pi@vm1","state":"done","exit_code":0,"result":{...}}
フィールド意味
host--host またはホスト一覧ファイルに記載されたとおりのマシン
statedone:コマンドが 0 で終了した。failed:そこで別のコードで終了した、またはここでの実行が失敗した。interrupted:実行が中断され、マシンがコマンドの終了を伝えてきた。may_still_run:ここで実行が中断され、マシンが待ち時間内にコマンドの終了を伝えてこなかった。not_started:マシンの順番が来る前に実行が中断された。そこでは何も実行されていない。
exit_codeマシン上でのコマンドの終了状態、またはここでの実行の終了状態:マシンに到達できなかった、または接続が切れた場合は 255、マシンがコマンドを実行できない場合は 3、実行が中断された場合は 130。kill の後の 137 など、ほかのコードはマシンのコードそのままで、状態は failed です。
resultコマンドが --json で出力したもの。内容は各コマンドのページに記載しています。agent logs では、その行の配列で、保持されるのは最大 16 MiB です。結果を出力して 1 で終了するコマンド(doctor、agent update)にも、このフィールドがあります。
errorコマンドが 0 で終了しなかった理由。kind と message を持ちます。ここでの実行のエラー(到達できなかったマシンでは種類 ssh で、メッセージの末尾に括弧で ssh のメッセージ)、それがなければコマンドのエラーオブジェクト、それもなければ終了コードと stderr の最後の行から作られたもの
outputコマンドが stdout に出力した、JSON ではないもの。16 MiB を超えて出力した場合は、その旨を示す文

stderr には、マシンの行とサマリーが出力されます。マシンの行には、--json でも自身の Error: の行を出力するコマンド(agent update)の、その行も含まれます。ここでの実行のエラーは、stdout の行にだけ含まれます。

# status が 0 で終了しなかったマシン ironflock --hosts line3.txt status --json 2>/dev/null | jq -r 'select(.state != "done") | .host'

複数のマシンでの Ctrl-C

Ctrl-C、SIGTERM、SIGHUP は、1 台のマシンでの実行と同じように実行を終了させます。そこでの各コマンドがシグナルを受け取り、各マシンには、コマンドの終了を確認するまで 15 秒の猶予があります。確認できなかったマシンは may_still_run です。順番が来ていないマシンでは何も実行されません。サマリーではそれらは not started と示され、コマンドは 130 で終了します。

複数のマシンで実行できるコマンド

コマンド複数のマシンでの実行
version、status、doctor、os images、os drives、agent restart、agent start常に可能
agent logs常に可能。ただし --follow は --json と組み合わせられません。マシンの行はコマンドの終了時に届きますが、--follow は終了しないためです
agent stop、agent update、agent configure、agent remove、os update、os rollback、self-update--yes を付けた場合のみ。これらは質問しますが、複数のマシンで同時に実行すると誰にも質問されないためです
completion--help と同じく、ここで応答し、どのマシンでも実行しません
agent install、os install、os flash、os reset不可。.flock ファイルが 1 台のデバイスを示すか、1 台のマシンを示す質問の後にディスク、ドライブ、デバイスのデータを消去するためです

このマシン上のファイルを指定するフラグは、複数のマシンでは拒否されます。ファイルがすべてのマシンに送られてしまうためです。doctor と agent configure の -c は、1 台のデバイスを示します。例外は agent configure の --proxy-password-file で、拠点のマシンで 1 つのプロキシアカウントを使うためのものです。

複数のマシンで実行できないコマンドラインは、ホスト一覧ファイルを読む前、どのマシンにも接続する前に、終了コード 2 で終了し、その理由を示します。

Last updated on