APCのSmart UPSで別OSの複数台を同時にシャットダウン

# 前提
今まで利用していた、電源をバックアップするだけのUPSは、電池交換になってしまったので、新しいモデルに買い換えることになりました。仕事で利用している環境は、CentOS7のデータサーバー・Windows10の経理PC・開発用のiMacです。せっかくUPSを買い換えるなら、この3台をすべて連動できないかと思いまして、APCのSmart-UPS SMT750Jを買うことにしました。

昔はマスターマシンとUPSは、シリアルポートを使って接続されていたようですが、今はUSBのType-Bケーブルを使って接続できるようになりました。ケーブルは付属されていないので、適当にType-BのUSBケーブルを購入しました。

# 構成
![構造.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74723/36735b61-a647-0637-34c6-fafe6332f94b.jpeg)

* マスター：CentOS7とUPSをUSBで接続
* スレーブ：LANにて共有

# セットアップ内容
* 配線
* 各マシンのIP固定
* ファイヤーウォール設定
* apcupsdのインストールと設定
* BOIS設定変更
* テスト

## 配線方法
上記の構成図のように、マスター（CentOS7）とUPS本体をUSBで接続します。次にマスターとスレーブのマシンが同じネットワーク内に入るように、LANハブに接続します。
ここで注意点が1つあります。マスターとスレーブマシンだけでなく、外付けのHDDケースやLANハブ、ルーターなどもUPSの電源につながっていることが重要です。

## 各マシンのIPを固定
まずは、各マシンにIPを手動で割り振るわけなので、ルーター側で同じIPを自動割り振りに使われては困ります。なので、まずはルーターの設定を変えることから始めます。

### ルーターの設定
私の環境はNURO回線にF660Tというルーターを利用しています。プロバイダーでくれるルーターにしては、様々なオプションが搭載されていて、その辺のルーターよりは使い勝手が良いです。もちろん数万円もするヤマハのルーターとは比べ物になりませんが…

ルーターの管理画面にログインしましたら、「ダイナミックアドレス管理」を開きまして、「DHCPプール開始IPアドレス」を変更します。

<img width="779" alt="スクリーンショット 2019-09-08 13.15.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74723/4fc3ae1b-9ca8-9518-7237-8b193de8ba8d.png">

私の場合は、他にも固定している機器がいくつかありますので、自動割り振りに利用されるアドレスを192.168.1.10〜にしています。
この設定をすることで、ルーター側では10番以降のIPアドレスを自動割り振りに使いますので、2〜9までは自分で設定しない限り使われることはありません。ちなみに、1番はルーター自身で使われています。

### OSごとにIPを固定
スクショを取るのが手間なので、下記に参考サイトをご参照ください。

Windows：https://support.eonet.jp/connect/net/multi_bbr/eo-rt100/quick/ip_static_win10.html
CentOS：https://qiita.com/tukiyo3/items/67182edee4f937e7f707
MacOS：https://pc-karuma.net/mac-static-ip-address/

私の環境では、下記のように設定しました。

Windows：192.168.1.3
CentOS：192.168.1.4
iMac：192.168.1.5

## ファイヤーウォール設定
場合によってはスレーブの設定も必要になることがあるようですが、私の環境ではマスターのみで大丈夫でした。今回はCentOSをマスターにしていますので、スレーブとの通信に使われる3551ポートをコマンドラインから開放します。

```ssh
$ firewall-cmd --zone=public --add-port=3551/tcp --permanent
```

## apcupsdのインストールと設定

### インストール

#### Windows&MacOS
macはbrewでもインストールできますが、インストール方法を統一するため、今回は下記からdmgとexeファイルをダウンロードして、インストールしました。
ダウンロード先：http://www.apcupsd.org/

#### CentOS
apcupsdには、「usbutils」パッケージと「libusb-1.0.so.0」コンポネントが必要なので、こちらをインストールします。

```ssh
$ yum install usbutils
$ yum install libusb-0.1.4-3.el7.x86_64
```

次にapcupsd本体をインストールします。

```ssh
$ wget http://springdale.math.ias.edu/data/puias/unsupported/7/x86_64/apcupsd-3.14.14-5.sdl7.x86_64.rpm
$ rpm -Uvh apcupsd-3.14.14-5.sdl7.x86_64.rpm
```

※ 最新版は http://springdale.math.ias.edu/data/puias/unsupported/7/x86_64/ にてご確認ください。

### apcupsdの設定

#### マスターマシンの設定

マスターマシンはUSBで接続していますので、USB専用の設定を行います。

```ssh:/etc/apcupsd/apcupsd.conf
# 接続設定
UPSCABLE usb
UPSTYPE usb
DEVICE

# 停電が起きてから、UPSが停電と認識するまでの時間
ONBATTERYDELAY 6

# ここまでバッテリー減ったら、シャットダウンを開始するバッテリー残量（%）
BATTERYLEVEL 10

# バッテリーの残り時間がこの分数に達したら、シャットダウンを開始する
MINUTES 3

# 停電状態をUPSが認識してから、シャットダウンに取り掛かるまでのタイムラグ（秒）
# ゼロにした場合は、「すぐにシャットダウンする」ということではなく、「この値をシャットダウンの条件に含まない」ことが注意点です。
TIMEOUT 5

# スレーブの有効化
NETSERVER on
NISPORT 3551
UPSCLASS standalone
UPSMODE disable
```

ここで注意しないといけないのが、**「シャットダウンを始めるための条件」**になります。

上記の条件では、
* 電源が供給されなくなった6秒後に停電と断定
* バッテリーが10%しか残っていなかったら、シャットダウンを開始
* または、バッテリーの持ち時間が残り3分を切っていたら、シャットダウンを開始
* または、停電状態だと断定されてから3秒が経過したら、シャットダウンを開始
という条件になります。

UPSを常にコンセントに繋げていると、充電量は100%の場合がほとんどです。また、繋がっている機器にもよりますが、3分は持つでしょう。なので、タイムアウトで設定している3秒が、もっとも早く選ばれる条件ではないかと思います。

よって、**「停電発生→6秒で停電と判断→3秒でシャットダウン開始」**というシナリオが上記設定で実現できると思います。

`TIMEOUT 0`にした場合はタイムアウトが考慮されないので、下記の動きになると思います。
**「停電発生→6秒で停電と判断→バッテリー残量が10%を切るか、バッテリーの残り時間が3分を切るかまで待つ→シャットダウンを開始」**

#### スレーブマシンの設定

スレーブマシンはLAN経由でシャットダウンしますので、LAN専用の設定を行います。
Windowsの設定ファイルは、`C:¥apcupsd¥etc¥apcupsd¥apcupsd.conf`にあります。
MacOSは、`/etc/apcupsd/apcupsd.conf`になります。

```ssh:/etc/apcupsd/apcupsd.conf
# LAN経由で通信
UPSCABLE ether

# マスターマシンのIPとポート
DEVICE 192.168.1.4:3551

# 上記と共通設定
ONBATTERYDELAY 6
BATTERYLEVEL 10
MINUTES 3
TIMEOUT 1
```

※ viで編集する場合は、管理者権限が必要なので、sudoを忘れずに付けること。

ポイントとしては、スレーブマシンをマスターマシンよりも早くシャットダウンさせることです。マスターマシンが先にシャットダウンしてしまいますと、マスターマシン側のapcupsdプロセスも落ちます。プロセスが落ちてしまうと、スレーブ側で停電を把握できず、そのままになってしまいます。

そのため、マスターマシンで`TIMEOUT`を利用して3秒間待ち、スレーブでは1秒しか待たない設定にしています。正確性はイマイチなので、他の意見がございましたら是非コメントください。
気になるとすれば、`POLLTIME`が60秒なので、上記のように2秒しか差がない場面でも動くかどうかですね。一応3回ほどテストして、問題はありませんでした。

## BIOSの設定変更
停電が発生すると、UPSを通じて各マシンがシャットダウンされます。一定時間が経つとUPSからの電源供給が止まります。最終的にはすべての電気が止まるわけです。
停電から回復すると、UPSの電源も回復しますので、このタイミングでシャットダウンされたマシンを起動させます。

### CentOSとWindows
電源が復帰した瞬間にPCを自動起動させるのは、マザーボードに依存する機能なので、ここに書いてあるやり方でうまくいかないこともあると思いますが、一応記録用に残しておきます。

私の場合は、CentOSとWindowsマシンのどちらもAsrockのマザーボードを使っているので、設定箇所も同じになります。

1. マシン起動時にF2を連打してBIOSに入る
1. Advancedモードを選ぶ
1. Chipset configurationを開く
1. Restore on AC/Power Loss項目を有効にする

### MacOS
Macの場合はBIOSがないので、環境設定と終了スクリプトを編集します。まずは、環境設定の「停電後に自動的に起動」オプションを有効にします。

<img width="668" alt="スクリーンショット 2019-09-08 13.23.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74723/e5774e21-7e25-1bc5-f21c-7a1e8c84b7cf.png">

次にスクリプトの編集ですが、下記の記事が参考になりました。
https://qiita.com/nagizero/items/e1c730424caa9ac634f3#mac

`/usr/local/etc/apcupsd/apccontrol`ファイルの`/sbin/shutdown`を`/sbin/shutdown -u`に書き換えます。

apcupsdをbrewでインストールすると上記のパスになりますが、私はdmgパッケージからインストールしたので、`/etc/apcupsd`直下にapccontrolファイルが入っています。viで書き換える場合は、sudoを忘れずに。

## テスト

テスト方法は至ってシンプルです。私が行った内容は下記になります。

* UPSの電源をコンセントから抜く
* 9秒間（6秒+3秒）経過すると、スレーブ側の電源が終了し始めます
* さらに待つと、マスター側のHDD回転が停止、後ほどシャットダウンする
* UPS側で電源供給停止までのカウントダウンが始まる（ディスプレイに秒数が出ます）
* UPSの電源供給が完全停止し、部屋が一気に静かになる
* UPSの電源をコンセントに戻します
* UPS側で電源供給開始までのカウントダウンが始まる（ディスプレイに秒数が出ます）
* UPSの電源が復旧し、マスターとスレーブマシンが自動的に起動します

ここまでできていれば、実際の停電時にも問題がないはずです。是非お試しください〜