一台の UPS と NAS と PC をすべて連携してシャットダウンさせたい - Asustor + APC 編2021/09/17 00:00

ASUSTOR NAS
近頃、SDE (Silent Data Error) という言葉をよく聞き、RAM等のソフトエラーだけでなく、HDD でも自然とデータ化けが起きることがあるとか。
確かにありえるし、気がついたらファイルがおかしくなっていた、というのも悲しいので、対策を考えた。

すると、いくつかの NAS で、RAID5 などパリティー型修復機構を持つ RAID 機構の場合、RAID scrubbing といってチェックをして再書き込みして修正してしまおう、という仕組みがあることがわかった。
でも、残念ながら古い Buffalo Linkstation には RAID scrubbing は無いらしい。

そこで、NAS を Buffalo Linkstation から、廉価な Asustor の 4 HDD 版に変えました。

ところが手持ちの Omron の UPS には対応していないので、UPS も APC 製に変更(APCは今シュナイダーエレクトリックなんですね)。

さらに、UPS/NAS と PC を連携してシャットダウンする自作プログラム "B-NAS Utils" も ASUSTOR+APC に対応させました。

B-NAS utils bnasupsc v1.6.0
http://www.ne.jp/asahi/net/pockey/program/bnasutils-1.6.0.zip

後で気がついたのですが、この RAID scrubbing、ASUSTOR の廉価版の場合は、毎回マニュアルで scrubbing をスタートさせる必要があり、定期的には実行してくれない。Asus のサポートに問い合わせると、自動実行機能は検討中だがいつ実装されるかはわからないとのこと。
Synology 社のはできる的なことが web にあるので、Synology 社のにすればよかったか、、、頑張れ Asus

Asustor 廉価版 NAS AS1xx4T の省エネ化2021/09/17 12:00

Buffalo の Linkstation NAS は、PC にソフトをインストールすれば、PC 立ち上げで NAS も立ち上がり、PC 終了で NAS もシャットダウンしてくれ、PC が複数台あっても対応できるし、非常に省エネな NAS でした。

ところが、Asustor の廉価版 NAS AS1xx4T は、HDDが停止する機能はあるが、15W 程度の消費があり(フル動作だと 30W くらいは消費している模様)、NAS 2 台つけていると常に 30W も消費していることになる。これは我が家の夜間消費電力の 10% を遥かに超えており、ちょっと嬉しくない。

Asustor の Intel CPU を使っている NAS の場合は、システム スリープ モード (S3)というものを持っていて、1.4W くらいに抑えることができるらしい。はやく言ってよ。もう2万出してこれ買っておけばよかった。。。
でもこの 2万をこの機能で償却できるのか、という疑問もある。

そこで、廉価版の NAS でも自動的にシャットダウンする仕組みを組めないか考えてみた。

幸いなことに、Asustor NAS には ssh が使える。

どの条件で自動シャットダウンしたいか、だが
1) Windows のファイル共有 (smb 接続)が存在しない
2) UPNP メディアサーバーでの配信が無い
は必須で、あと簡単に自動シャットダウンをさせない機構もほしいので
3) ssh セッションが生きていないこと(自動シャットダウンさせないときは、どこからか ssh terminal を開いておくことにする)
あと、
4) RAID scrubbing が実行されていないこと
も入れたい。

上記条件を検知して、条件を満たした状態が例えば15分続いたら自らを poweroff するスクリプトを書き、NAS shell で定期的に実行させればいいかも。と思っていたのだが、残念ながら NAS の cron が使えない。
/etc 以下にあるファイルを編集しても、NAS を再起動するといじれるシステム環境は初期化されてしまうという、よくある実装でした。

さて、それなら ssh を使って 外部から poweroff をしてあげればいい。家に低消費電力な常時通電 Linux も動いている (Raspberry pi の初期のもの)。

admin パスワードのやり取りが必要なので、セキュリティー的に心配だが、家庭内だし、マシン間通信がセキュアならまあいいか。

実装概要としては
a) poweroff 条件をチェックして自らを poweroff する NAS 上で動作する sh スクリプトを書く
b) a) を外部(Host) Linux から NAS にロードして、定期的に NAS 上での実行をかける (Host Linix の cron を使う)

その2へ続く。。。

Asustor 廉価版 NAS AS1xx4T の省エネ化 - その22021/09/18 00:00

事前準備
- NAS に、admin 権限のアカウントを作っておく(例えば adminx). admin アカウントを使ってもいいが、この目的専用の password にしておきたかった、というだけの理由。
- NAS の ssh サービスを有効にしておく
- 同じネットワーク上に常時動作してある linux を使う (Raspberry PI など)

下記 5 つのファイルを作成し、Linux host で crontab 設定する。

NASをリモート起動する場合は、WOL を使用(NAS の WOL 設定をお忘れなく)。

1) auto_poweroff.sh - NAS 上で動かすスクリプト
#!/bin/sh
PASSWD="adminx アカウントのパスワード平文"
SMBLOG="./smbstatus.log"
NSLOG="./netstat.log"
LOCKFILE="./auto_poweroff.lock"

## RAID scrubbing check
ps -ef | grep  "\[md1_resync\]"
if [ $? -eq 0 ]; then exit 0; fi
## RAID scrubbing check -- end

## established session check (UPNP, ftp, sftp, ssh)
netstat -ut > $NSLOG
M=`cat $NSLOG | wc -l`
while [ $M -gt 0 ]; do
        LINESTR=`sed -n $M\P $NSLOG`
        echo $LINESTR | grep -E "^(tcp|udp)" > /dev/null
        if [ $? -eq 0 ]; then
                SESSION=`echo $LINESTR | awk -F' ' '{print $6}'`
                if [ $SESSION = "ESTABLISHED" ]; then
                        IPPORT=`echo $LINESTR | awk -F' ' '{print $4}'`
                        echo $IPPORT | grep -E ":(5001|2222|ftp)$" > /dev/null
                        if [ $? -eq 0 ]; then break; fi
                        echo $IPPORT | grep -E ":ssh$" > /dev/null
                        if [ $? -eq 0 ]; then
                                CLIENT=`echo $LINESTR | awk -F' ' '{print $5}'`
                                CLIENTNAME=`echo $CLIENT | sed -e "s/^\(.\+\):[0-9]\+$/\1/g"`
                                IPADDR=`nslookup $CLIENTNAME | grep "Address" | tail -n 1 | sed -e "s/^Address.*:[ \t]\+\([0-9a-fA-F.:]\+\).*/\1/g"`
                                IPPORT="$IPADDR:`echo $CLIENT | sed -e "s/^.\+:\([0-9]\+\)$/\1/g"`"
                                SSHCLIENT="`echo $SSH_CLIENT | awk -F ' ' '{print $1}'`:`echo $SSH_CLIENT | awk -F ' ' '{print $2}'`"
                                if [ $IPPORT != $SSHCLIENT ]; then break; fi
                        fi
                fi
        fi
        M=`expr "$M" - 1`
done

if [ $M -gt 0 ]; then
        echo "$LINESTR"
        rm -f $LOCKFILE
        exit 0
fi
## UPNP session check -- end

## samba session check
echo $PASSWD | sudo -S /usr/builtin/bin/smbstatus -A > $SMBLOG
N=`cat $SMBLOG | wc -l`
while [ $N -gt 0 ]; do
        IPADDR=`sed -n $N\P $SMBLOG | awk -F' ' '{print $5}'`
        echo $PASSWD | sudo -S ping -c 1 -W 3 $IPADDR > /dev/null
        if [ $? -eq 0 ]; then break; fi
        N=`expr "$N" - 1`
done

if [ $N -gt 0 ]; then
        echo "IP $IPADDR is alive."
        rm -f $LOCKFILE
        exit 0
fi

if [ -e $LOCKFILE ]; then
        echo 'Execute poweroff'
        rm -f $LOCKFILE
        echo $PASSWD | sudo -S poweroff
        exit 2
else
        echo 'Check one more time later'
        echo -n > $LOCKFILE
fi

exit 1
2) sendscript.sh - 上記実行ファイルの転送と実行を host 上で行う script
#!/bin/bash
if [ $# -ne 1 ]; then
        echo "Usage: $0 [nas_server_address]"
        exit 2
fi

THIS_FILE_PATH=`dirname $0`
PASSWD="adminx アカウントのパスワード平文\n"

echo "["`date "+%Y%m%d_%H%M"`"]"

ping -c 1 -W 3 $1 > /dev/null
if [ $? -ne 0 ]; then
        echo "Target $1 in power-off. Quitting..."
        exit 1
fi

expect -c "
        set timeout 30
        spawn $THIS_FILE_PATH/chkfile.sh $1
        expect \"Password:\"
        send $PASSWD
        expect eof
        catch wait result; exit [lindex \$result 3]
"

if [ $? -ne 0 ]; then
        expect -c "
                set timeout 30
                spawn $THIS_FILE_PATH/scp.sh $1
                expect \"Password:\"
                send $PASSWD
                expect eof
                catch wait result; exit [lindex \$result 3]
        "
fi

expect -c "
        set timeout 30
        spawn $THIS_FILE_PATH/ssh.sh $1
        expect \"Password:\"
        send $PASSWD
        expect eof
        catch wait result; exit [lindex \$result 3]
"
3) scp.sh - 実行ファイル転送サブ・スクリプト
#!/bin/bash
THIS_FILE_PATH=`dirname $0`
scp -p $THIS_FILE_PATH/auto_poweroff.sh adminx@$1:./
4) ssh.sh - 転送スクリプトを実行させるサブ・スクリプト
#!/bin/bash
ssh adminx@$1 "./auto_poweroff.sh" 
5) chkfile.sh - 実行ファイルが NAS に存在するかを調べるサブ・スクリプト
#!/bin/bash
ssh adminx@$1 "ls ./auto_poweroff.sh"
exit $?
6) 上記 5 つのファイルをホスト Linux 上の同じディレクトリに置き(例では、~/nasctrl/)、chmod 750 としておく. Root である必要はなく、単なる 1 ユーザアカウントで OK.

7) ホスト Linux での crontab -e
NAS の I{P が 192.168.1.91 だった場合の例
*/15 * * * * ./nasctrl/sendscript.sh 192.168.1.91 >> ./nasctrl/nas01.log 2>&1

今回仕掛けた自動 poweroff 機構を簡単に一時停止したい場合の手段として、NAS での ssh session を開いていれば poweroff しない、という細工をしたのだが、poweroff を司るスクリプトの実行自体 NAS への ssh なので、永遠に poweroff しないというおマヌケな自体に陥った。とりあえず、の対策部がなんともイケてない。。。