sironekotoroの日記

Perl で楽をしたい

autossh を macOS 起動時に実行する

macOS 起動時に autossh を実行したい

autossh という ssh のラッパーソフトがあり、sshが切れたら自動的に繋ぎ直してくれるという便利なやつです。

autossh は homebrew で入れられます。

これを ターミナル起動時 ではなく、macOS の起動時に自動実行させたいという要望です。

まずは普通にターミナルから実行できるか試す

うちの場合はこんな感じでした。

$ ssh -L 127.0.0.1:${LOCAL_PORT}:${SERVER_IP}:${SERVICE_PORT} -i ~/ssh/id_rsa -l ${LOGIN_NAME} -p ${SERVER_PORT} ${SERVER_ID}

ローカルポートにアクセスすると、サーバーの特定のサービスポートにつながる、いわゆるトンネルを掘るというやつです。

これを autossh に書き直すとこんな感じ。

${LOCAL_PORT} とかは 実際には 22 などのポート番号、${LOGIN_NAME} には sironekotoro とかの文字列が入っております。

$ autossh -M 0 -f -N -L 127.0.0.1:${LOCAL_PORT}:${SERVER_IP}:${SERVICE_PORT} -i ~/ssh/id_rsa -l ${USERNAME} -p ${SERVER_PORT} ${SERVER_ID}

これをターミナルから実行して、ちゃんとトンネルが掘れたことを確認。

これを launchd の作法で書くだけで大丈夫なはず!

launchd で動かせない

大丈夫じゃなかった。ダメでした。

もう、何がダメかわからないレベル。

これが動かなかった plist です。供養。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>local.mxcl.autossh</string>
    <key>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin</string>
    </dict>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/autossh</string>
        <string>-M</string>
        <string>0</string>
        <string>-f</string>
        <string>-N</string>
        <string>-p</string>
        <string>${SERVER_PORT}</string>
        <string>-l</string>
        <string>${LOGIN_NAME}</string>
        <string>-i</string>
        <string>/Users/${USERNAME}/.ssh/id_rsa</string>
        <string>-L</string>
        <string>127.0.0.1:${LOCAL_PORT}:${SERVER_IP}:${SERVICE_PORT}</string>
        <string>${SERVER_IP}</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/Users/${USERNAME}/Desktop/standard_out.txt</string>
    <key>StandardErrorPath</key>
    <string>/Users/${USERNAME}/Desktop/standard_error.txt</string>
  </dict>
</plist>

エラーを吐き出すようにしてるけど、standard_error.txt には、autossh を引数なし(あるいは不正な引数)時の usage が出力されてるのみ。

で、最小限の引数でってことでバージョンを表示する -V オプションだけを入れると、ちゃんと standard_out.txt にバージョン番号が追記される。

ぐぐぐぐ。

    <array>
        <string>-V</string> 
    </array>

なお、launchd ではシェル変数とかホームディレクトリを表す ~ とかが展開されないってことに気づくのにえらい時間がかかった。

基本に立ち返る

いやいや、俺は致命的な勘違いをしているのかも。

よくやるじゃん致命的な勘違い。

ってことで、ファイルを作るだけの簡単なやつで試してみる。

$ cd ~/Library/LaunchAgents
$ touch local.test.touch.plist

作った local.test.touch.plist は以下の内容で編集する

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>local.test.touch</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/touch</string>
        <string>/Users/sironekotoro/Desktop/test.txt</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/Users/sironekotoro/Desktop/standard_out.txt</string>
    <key>StandardErrorPath</key>
    <string>/Users/sironekotoro/Desktop/standard_error.txt</string>
  </dict>
</plist>

作ったら、文法に間違いないか確認する

$ plutil -lint local.test.touch.plist
local.test.touch.plist: OK

ではいざ実行!

$ launchctl load local.test.touch.plist

これでうまく動いて、デスクトップ上に text.txt という空のファイルができた。

うん、間違ってない・・・となると何故 autossh は動かないのか。

とりあえず、後片付け。

$ launchctl unload local.test.touch.plist
$ rm local.test.touch.plist

ワークアラウンド

いいかげん、あれこれ試すのも飽きてきたので、諦めてワークアラウンド(回避策)さがす。

Autometer でコマンド実行するやつを作って、それを 環境設定 → ユーザとグループ のログイン項目に入れる

Autometer 単体ではちゃんと動いた。

でも、macOS 起動時になぜか、なぜか、Xcode が立ち上がる。なんで???

autossh のコマンド入れたシェルクスリプト作って、それを launchd から呼ぶ

これはうまくいきました。

autossh.sh というファイルを以下の内容で作って

#!/bin/bash
/usr/local/bin/autossh -M 0 -f -N -L 127.0.0.1:${LOCAL_PORT}:${SERVER_IP}:${SERVICE_PORT} -i ~/ssh/id_rsa -l ${LOGIN_NAME} -p ${SERVER_PORT} ${SERVER_ID}

実行権限つけておきます。

$ chmod +x autossh.sh

このファイルを起動する plist を作ります。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>local.mxcl.autossh</string>
    <key>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin</string>
    </dict>
    <key>ProgramArguments</key>
    <array>
        <string>/Users/${USERNAME}/autossh.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/Users/sironekotoro/Desktop/standard_out.txt</string>
    <key>StandardErrorPath</key>
    <string>/Users/sironekotoro/Desktop/standard_error.txt</string>
  </dict>
</plist>

あとはさっきの touch の時のように起動時のリストに登録・・・これで動きました。

本当は、シェルスクリプト通さずに plist の中身だけで autossh を実行したかったんですが、今はこれが精一杯ってことで。

お疲れ様でした。