Raspberry PiのIPアドレスをSlackで調べられるようにするデーモン

Raspberry Piを運用していると、固定IPを用意できなかったり、様々なネットワークに持ち込む度に毎回IPアドレスが変わってしまい、モニタを接続してIPを調べたり、 `arp-scan` コマンドで探したりするのがそれなりに大変であるということがあります。

Raspberry Piを持ち込んだ先でsshで繋いだり、HTTPのサービスに繋ぎたいのにIPがわからなくて苦労した経験がある人も多いのではないかと思います。

だったらRaspberry Piが起動した時に自動的にSlackにボットとして接続して、そのボットに問い合あわせたらIPを教えてくれるようにすれば良いよね、というのがこのやり方です。

[sifue/notice-ip-to-slack](https://github.com/sifue/notice-ip-to-slack)

以上のPython製のデーモンツールを作りましたので、インストールして利用します。

### Slack のボット作成

![スクリーンショット 2019-02-08 20.57.44.png](https://qiita-image-store.s3.amazonaws.com/0/2382/e2176a04-9ca8-fc7d-e0ae-9640f337a57e.png)

予め自分がボット作成権限を持つSlackで、その他の管理項目 > App 管理 にて Hubot を選択して、 ボットの API トークンを取得しておきます。また、ボット名などもここで設定しておきましょう。

```
xoxb-XXXXXXXXXXXXXXXXXXXXXXXX-XXXXXXXX-XXXXXXXX
```

このようなトークンになります。あとはそのボットを適当なチャンネルに招待しておきます。

### ボットの設定

次に `notice-ip-to-slack` を zip でダウンロードするなり、git clone するなりして手に入れます。 最新のラズパイには Python3 は入っているはずなので、

```
sudo pip3 install slackbot
```

にて[slackbot](https://github.com/lins05/slackbot) をインストールします。

そしてボットトークンの設定です。

```
cp slackbot_settings_template.py slackbot_settings.py
vi slackbot_settings.py
```

以上で編集して、

```
# -*- coding: utf-8 -*-

API_TOKEN = "xoxb-XXXXXXXXXXXXXXXXXXXXXXXX-XXXXXXXX-XXXXXXXX"

default_reply = "notice-ip-to-slack running."
```

このように自分のトークンを設定します。この時点でボット自体の設定は完了です。

ボット自体は `./run.py` で起動できますので、もしこの時点で動作確認したければ起動しましょう。

```
If you exec as not service, a permission error occurs. Please ignore and kill a child process.
```

と表示されてPIDファイルが作れないエラーが出ますが、これはデーモン登録時は大丈夫ですので無視しましょう。

ボットに `@ボット名` というメンションを送って `ip addr` の結果を答えてくれれば成功となります。

```
ps aux | grep python3
```

にてデーモンとして起動した子プロセスを見つけて

```
kill {プロセスID}
```

で子プロセスを終了しておきましょう。ちなみにコードの中身はこの様になっています。

```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import subprocess

from slackbot.bot import Bot
from slackbot.bot import respond_to

@respond_to(r'.*')
def mention_func(message):
    message.reply(subprocess.check_output("ip addr", shell=True))

def main():
    bot = Bot()
    bot.run()

def daemonize():
    pid = os.fork()
    if pid > 0:
        print("If you exec as not service, a permission error occurs. Please ignore and kill a child process.")
        print("Parent process pid: {}".format(pid))
        pid_file = open("/var/run/notice-ip-to-slack.pid", "w")
        pid_file.write(str(pid) + "\n")
        pid_file.close()
        sys.exit()
    if pid == 0:
        print("Child process pid: {}".format(pid))
        main()

if __name__ == "__main__":
    daemonize()
```

slackbot の仕様に合わせてなにかメンションをもらうと `ip addr` のコマンド結果を返すように実装しています。またデーモン化はスクリプトの実行と同時にプロセスをフォークして2つに分割し、親プロセスはプロセスファイルを書いて終了、子プロセスはデーモンとして生き残るような処理を記述しています。

### デーモンの設定

引き続き、

```
vi noticeiptoslack.service
```

にてユニット定義ファイルを設定します。 

```
[Unit]
Description=NoticeIpToSlack

[Service]
ExecStart=/home/pi/workspace/notice-ip-to-slack/run.py
Restart=always
Type=forking
PIDFile=/var/run/notice-ip-to-slack.pid

[Install]
WantedBy=multi-user.target
```

この度は、 ExecStart を `/home/pi/workspace/notice-ip-to-slack/run.py` に設定してありますが、自分が notice-ip-to-slack を展開しているパスにあわせてください。


最後に、権限の設定から systemctl への登録、自動起動までを一気に設定します。

```
sudo chmod 755 -R .
sudo cp noticeiptoslack.service /usr/lib/systemd/system/
sudo systemctl daemon-reload
sudo systemctl start noticeiptoslack.service
sudo systemctl enable noticeiptoslack.service
```

これで完了です。

```
sudo shutdown -h now
```

以上のコマンドでシャットダウンした後、ラズパイを再度起動し、Slackのボットに @ボット名 のメンションを飛ばしたら `ip addr` のコマンド結果を教えてくれるようになったら成功となります。

![スクリーンショット 2019-02-08 20.53.20.png](https://qiita-image-store.s3.amazonaws.com/0/2382/743d7d52-3c78-2d6c-eb20-8e7752cf03a1.png)

このようになります。お疲れ様でした。

### 追伸

もし仮にラズパイを盗まれたり、紛失した際には、トークンが流出してしまうので、しっかりSlack上からトークンの失効や再発行をするようにしましょう。

あと、cpコマンドにsudoが着いていなかったりした点を修正したり、deamonizeをうまく呼べてなかった点を修正しました。

### 参考

- [PythonのslackbotライブラリでSlackボットを作る](https://qiita.com/sukesuke/items/1ac92251def87357fdf6)
- [pythonをデーモン化するメモ](https://qiita.com/croquisdukke/items/9c5d8933496ba6729c78)