Wake on LAN してみる Part 3 (shutdown)

前回までで、とりあえず リモートで PC を起動できるようにはなったのだが...
今更ながら気づく。リモートで起動できるのに リモートでは停止できないことに...
これでは 必要な時だけサーバを起動しておくという当初の目的が達成できない。

もちろん、リモートログインすれば PC を停止できる。
でも、PC を停止するためだけに 毎回 リモートログインして shutdown コマンドを実行するのも面倒...
特に WindowsSSH クライアントが標準装備されていないし...

と言うことで...
今回は リモートで Linux サーバを停止するための処理を JavaFX で実装してみた。
ちなみに 今回 対象とする Linux ディストリビューションUbuntu だけ...
他のディストリビューションでも停止できるかどうかは不明。

JavaFX で ネットワーク上の Linux サーバを停止するのもそれほど難しくはない。
要は自分自身が行っている

  1. Linux サーバにリモートログインする。
  2. root 権限で shutdown コマンドを実行する。
といった手続きをプログラムするだけ...
当然 リモートログインは SSH で行います。
もちろん Telnet でもできますが 今時 Telnet でログインできるサーバなんてありえない...

と言うことで、
JavaFXSSH してみることに...

残念ながら Java の標準APISSH をサポートしていないので 別途ライブラリが必要になる。
SSH 用のライブラリはいくつかあるようだが 今回は 一番メジャーと思われる JSch を使うことにした。
まず、jsch-x.y.z.jar をダウンロードして クラスパスに追加しておく。

後は 以下のように実装するだけ...
例のごとく 例外処理等は全く考慮していません。

import java.io.ByteArrayInputStream;
import java.lang.*;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;

// サーバ情報
def host = "192.168.1.1";
def port = 22;

// ユーザ情報
def username = "hoge";
def password = "pass";

// shutdown コマンド
def command = "sudo -S -p '' /sbin/shutdown -h now";

def jsch = new JSch();
def session = jsch.getSession(username, host, port);

try {

    // SchException: UnknownHostKey を防ぐための設定
    session.setConfig("StrictHostKeyChecking", "no");
    session.setPassword(password);
    session.connect(5000);

    var channel = session.openChannel("exec") as ChannelExec;

    try {
        channel.setCommand(command);

        channel.setInputStream(new ByteArrayInputStream("{password}\n".getBytes()));
        channel.setOutputStream(System.out);
        channel.setErrStream(System.err);
        channel.connect();

        // コマンドが終了するまで待機
        while (not channel.isClosed()) {
            Thread.sleep(1000);
        }

    } finally {
        channel.disconnect();
    }

} finally {
    session.disconnect();
}

JSch の使い方は Examples を参照すれば大体わかるはず...

今回の実装は

echo "pass" | ssh hoge@192.168.1.1 "sudo -S -p '' /sbin/shutdown -h now"
のように ssh コマンドを実行しているのとほぼ同じです。
ちなみに、上記のコマンドは リモートサーバ上で sudo して root 権限で shutdown コマンドを実行しています。

通常 sudo コマンドを実行するとパスワードを要求してきますが、"-S" オプションを付けることで 標準入力からパスワードを渡すことができるので、 『echo "pass"』で出力したパスワードをパイプ ( | ) で渡しているのです。
で、プログラムでは このパスワードの渡し方を

channel.setInputStream(new ByteArrayInputStream("{password}\n".getBytes()));
で実現しています。
パスワードの最後に改行コードを付けるのを忘れないように注意しましょう。
この辺りの話は 『sudo をプログラムで使う際の注意点』 にまとめてありますのでよかったらどうぞ...

以上のように JavaFXSSH を利用するのは とても簡単です。
SSH には この他にも まだまだ いろいろな使い道がありそうですね。
サーバを操作したり、サーバの情報を参照したりする ちょっとしたクライアントツールが簡単にできちゃいます。

今回のサンプルも まだ画面がないので はっきり言えば JavaFX で実装する意味はほとんどないですが...
一応、コマンドラインから

javafxc -classpath jsch-x.y.z.jar Main.fx
javafx -classpath .:jsch-x.y.z.jar Main
と入力すれば実行できます。興味のある方は ぜひ試してみてください。