2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

slackへの書き込みをmattermostに連携してみた

Last updated at Posted at 2018-08-16

やりたかったこと

飲みすぎた・・・明日もう会社やすみたい・・・
でも、その手の連絡はmattermostでやることになっていて、家から連絡しようにもF/Wで閉じられてるしなぁ・・・
VPNを通せばいいのだけれど、それも面倒だし・・・
っていうかスマホからさくっと連絡すませたい・・・

ということで、slackとmattermostを両方使っているという謎運用を利用して、
slackの特定チャンネルに投げるとmattermostにも流れるようにできないか、とチャレンジしてみた。

使用言語はpythonだが、超初心者なのでその辺はご勘弁ください。

構成(イメージ)

  • slack
    • 無料範囲で利用
    • mattermost連携用の専用チャンネルを作る
    • botを登録し、専用チャンネルに紐付ける
  • mattermost
    • 5.1.0 on CentOS7(たぶんどのバージョンでも動く)
    • slackから投げられる専用チャンネルを作る
    • Incomming-Webhookを登録
  • mattermostにhookできるIPを持ったサーバ上のツール
    • Python3.6.4 on CentOS7(python2系使うならurllib3まわりを修正する必要アリ)
      • 面倒なのでmattermostサーバに同居させた
      • INは絞られていてもかまわないが、OUTはslackへの到達性が必要なので、注意
    • slackに情報を取りに行く
    • その情報をmattermostに投げる
    • 常時起動しておきたいので、systemdに登録

slackにBotを登録 & mattermostにwebhookを登録する

webでもqiitaでもいい記事がいっぱいあるので、ここでは、割愛。

slackからとってくるClass

zukaさんのブログを参考に、python-slackclientを利用。
ちょっと古いバージョン(1.2.1)でよければ、githubからとって来なくとも普通にpip install slackclientでとってこれた。

class_SlackReader
import time
from slackclient import SlackClient

slack_token        = "slackで発行したBotのtoken"

class SlackReader:
    def __init__(self):
        self.slack = SlackClient(slack_token)
        if self.slack.rtm_connect():
            while True:
                data = self.slack.rtm_read()
                if len(data) > 0:
                    for item in data:
                        if item["type"] == "message":
                            ### mattermostに投げる処理
                    continue
                else:
                    time.sleep(30)
        else:
            print("Connection Failed")

古いバージョンなら普通にインストール可能、と先に書いておきながら、
実は古いバージョンにはrtm_readした際にメッセージを1個しかとってきてくれないバグがある。
そのため、メッセージ取得に成功した場合は、sleepせずにcontinueで再度取得している。

mattermostに投げるClass

これは、以前に自分で適当に作ったclassを少しいじって流用。
urllib3で所定のフォーマットで投げるだけ。

class_MattermostSender
import json
import requests
import urllib3
from urllib3.exceptions import InsecureRequestWarning
urllib3.disable_warnings(InsecureRequestWarning)

mattermost_url     = "mattermost-hookのURL"
mattermost_channel = "投げたいチャンネル名"
mattermost_iconurl = "/static/emoji/1f43c.png" # パンダ

class MattermostSender:
    def __init__(self, message_data):
        self.post_data = {
            "channel"  : mattermost_channel,
            "icon_url" : mattermost_iconurl,
            "username" : message_data["user"],
            "text"     : message_data["text"]
        }
    
    def send(self):
        headers = {'content-type': 'application/json;charset=UTF-8'}
        try:
            r = requests.post(mattermost_url, headers=headers, data=json.dumps(self.post_data), verify=False)
        except Exception as curl_error:
            print(str(curl_error))
            sys.exit()

InsecureRequestWarningしているのは、検証環境がオレオレのため。
正規証明書の環境でだけ動かすなら、もちろん消す方が良い。

systemdで起動

上記を組み合わせた一枚モノのpythonコード(slack-feed.py:仮称)を、あとはsystemdで起動すればOK
以下はとりあえず動かす用でだいぶ適当な例

/etc/systemd/system/slack-feed.service
[Unit]
Description=slack-feed
After=syslog.target network.target

[Service]
Type=simple
User=root
Group=root
ExecStart=/path/to/slack-feed.py
PrivateTmp=yes
Restart=no
RestartSec=30

[Install]
WantedBy=multi-user.target

一応、動きはした

改善点はあるものの、一応到達はした。
これで自分用のスマホからでも、会社に「ちょっと体調悪いことにして休みます〜」とメッセージが投げれるようになった!
よし、休もう!

  • 改善点
    • slackのuserはよくわからんIDになっているので、見てわかるユーザー名に変えてやる必要がある
    • そのついでに、アイコンがパンダ固定なのもなんとかしたいところ
    • slackサーバ側の負荷を考慮して同期間隔を30秒にしたが、もう少し短くても大丈夫かも
    • そもそもslackをメインの運用にしてればこんなことしなくて済んだのに。

slack-feed.py全貌

説明の都合上小分けにしたので、最後にあらためてpythonファイルの全貌を。

slack-feed.py
#!/path/to/python
# -*- coding: utf-8 -*-
import sys,os
import re

### slackからとってくるのに使用
import time
from slackclient import SlackClient

### mattermostに送るのに使用
import json
import requests
import urllib3
from urllib3.exceptions import InsecureRequestWarning
urllib3.disable_warnings(InsecureRequestWarning)

### 設定
mattermost_url     = "https://mattermost/hooks/hogehoge"
mattermost_channel = "slack-channel"
mattermost_iconurl = "/static/emoji/1f43c.png"
slack_token        = "hogepiyo"

### mattermostにメッセージ送信するクラス
class MattermostSender:
    ### init:送信データを辞書形式で作成
    def __init__(self, message_data):
        self.post_data = {
            "channel"  : mattermost_channel,
            "icon_url" : mattermost_iconurl,
            "username" : message_data["user"],
            "text"     : message_data["text"]
        }
    
    ### データをmattermostに送信する
    def send(self):
        headers = {'content-type': 'application/json;charset=UTF-8'}
        try:
            r = requests.post(mattermost_url, headers=headers, data=json.dumps(self.post_data), verify=False)
        except Exception as curl_error:
            print(str(curl_error))
            sys.exit()
        
class SlackReader:
    def __init__(self):
        self.slack = SlackClient(slack_token)
        if self.slack.rtm_connect():
            while True:
                data = self.slack.rtm_read()
                if len(data) > 0:
                    for item in data:
                        if item["type"] == "message":
                            MattermostSender(item).send()
                    continue # slackclientのバグで一個しかとってこない(issue #231)ので、再度投げる
                else:
                    time.sleep(30)
        else:
            print("Connection Failed")
 
###### MAIN SCRIPT ######
if __name__ == '__main__':
    SlackReader()
2
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?