Linux停電時にシャットダウンする方法考えてみた

こんにちはRcatです。
この季節、大雨雷最近多いですよね。そんなこともあろうかとUPSを導入しているのですが、最近導入した24時間サーバーについて問題があります。
問題とはズバリ常時そばににいるわけではないのでシャットダウンできないということです。これでは予備電力が尽きた時、結局落ちてしまいます。
UPSに何かソフトがついていたような気もしますが、Linuxで動くとも限らないので、今回はそういったメーカーのソフトなどに頼らず、どんな環境でも動作するような方法を考えていきます。


切り口

概要

今回問題となっているのは24時間運用のサーバーが停電時シャットダウンできないということですね。
しかし、このサーバーで常時満足している条件が1つあります。それはネットワークに接続しているということです。
そしてUPSはパソコンにしか繋がっていません。つまり、停電時ルーターやハブの電源は落ちます。それはつまりサーバーがスタンドアローンになるということです。
というわけで、切り口としては自身がスタンドアローンであるかどうかを判別し、スタンドアローンであった場合はシャットダウンするというサービスを考えていきます。

どういうコマンドがあるか

サクッと聞いてみました。

とりあえず上に2つは使えそうですね。
勘違いしやすいのは一番下で、今回判定したいのはインターネットに接続しているかどうかではなくネットワークに繋がっているかどうかを判定したいのですね。なので、外部にネットワークへの接続可否の判定は今回は使いません。

実際にやってみる

ipコマンドで判定

今回はいくつか試して一番使いやすそうだったIPコマンドを使います。

普通の状態の場合は以下のような出力が得られました。
一番上のdefaultが有線のネットワークです。
他にもいくつかありますが、VPNやDockerのネットワーク関係も入ってきてるみたいですね。

ちなみにそういった余計なものがない状態のパソコンだとこんな感じになります。
一番最初の方はイーサネットケーブルを抜いた状態でコマンドを実行、途中の出力があるところがケーブルを挿した状態で実行した内容です。終了コードは常時0のようですね。
これを見る限り、イーサネットとそれに関連するものだけだった場合は、スタンドアローンになると完全に出力が消えるみたいです。

この場合は簡単なのですが、今回のように他のネットワーク関係のものが入っていると出力が完全になくなるわけではないので、少し内容を吟味する必要があります。

ソースコード

とても適当ですが、こんな感じでしょうか?

具体的には事前にチェック間隔とシャットダウンまでの時間を設定しておき、それに沿って確認が行われます。
今回は5分以上スタンドアローンだった場合、シャットダウンという風にしてみました。
また、単純に事故でケーブルが抜けたり、ルーターの電源が落ちているなんて可能性もあるので、ネットワークに戻った際はタイマーをリセットするようにもなっています。

もう一つのポイントとしては、出力内容の有無だけだと環境によっては判定できないので、defaultの行があるかどうかという判定も入れています。
最後に、シャットダウン時はコマンドを実行ですね。
このコマンドはrootでないと打てないので、このスクリプトはrootで実行します。

実際の結果

最初にイーサネットケーブルを抜いて放置するとスタンドアローンが検知されました。
その後挿しなおしたところ復帰し、キャンセルされることを確認。

シャットダウンの絵が無いって…?秒で落ちるので撮ってません…。

配布&使い方

導入方法

今回の配布システムは以下の3つのファイルで構成されています。
事前にスクリプト本体が起動することを確認の上、systemdに登録してください。標準ライブラリしか使っていないので基本的に立ち上がるはずです。

また、サービスファイルのうち、以下赤枠で囲った場所は各自のパスに書き換えてからサービス登録をしてください。

サービスファイルについては以下の記事で紹介していますので、よろしければ参考にしてください。

配布

以下のURLから今回作成したものを配布しています。
利用規約に同意の上ご利用ください。

https://script.google.com/macros/s/AKfycbxdcr8pnazR7RbjaSICTtaNWfN7h_rjQrKlZ3h9CZpPRFzRILk1OGc8mZqKbF-NXNO9/exec?name=UPSシャットダウンサービス


情報が役に立ったと思えば、僅かでも投げ銭していただけるとありがたいです。