LoginSignup
2
2

More than 3 years have passed since last update.

Go で ChatOps 用 bot 作成ハンズオン

Last updated at Posted at 2019-05-30

社内のハンズオン向けに書いていた資料ですが、まぁ Public Qiita でも差し支えない内容だったしそれなりに良い内容にまとまったと思ったので公開します。

※ 筆者の Go 力は「たったの 5 か、ゴミめ」レベルなので解説とか間違いの指摘大歓迎

背景

ChatOps したい。したくない?
Go で Slack bot 作ると結構簡単に ChatOps できるよ。

使うもの

ハンズオン

Go をインストールしよう

筆者は公式サイト派。.pkg なのでダブルクリックするだけ。
https://golang.org/dl/

$ go version
go version go1.12.5 darwin/amd64

一瞬。

Homebrew でもインストールできるらしいがやってない。

Go で Hello, World してみよう

まぁ定番ですよね。
インタプリタは無いので、vim で書きます。
vim じゃない人は知りません、お使いのエディタで書いてください。

hello.go
package main

import "fmt"

func main() {
    fmt.Println("Hello, world.")
}

go run で実行。

$ go run hello.go
Hello, world.

簡単ですね。
ビルドもしてみましょう。

go build

$ go build hello.go
$ ls
hello       hello.go
$ ./hello
Hello, world.

とっても簡単ですね。
ちなみにちょっと間違えてみましょう。

hello.go
  1 package main
  2
  3 import "fmt"
  4
  5 func main() {
  6     hello = "Hello, world."
  7     fmt.Println(hello)
  8 }
$ go build hello.go
# command-line-arguments
./hello.go:6:2: undefined: hello
./hello.go:7:14: undefined: hello

hello は宣言されていない変数のため、値の代入時に「hello なんて宣言されてないよ」と怒られています(6 行目)。
また、宣言できていないため、7 行目の fmt.Println での呼び出しについても怒られています。
コンパイルは実行前にエラーが分かっていいですね。

ちょっと解説

package は Go で名前空間を定義するために使うようです。
一つのファイルに全部書いちゃうなら、main だけでいいですね。
http://cuto.unirita.co.jp/gostudy/post/go-package/

余談

筆者は vim-go 使ってます。
が、特にこれと言って機能を使い込んでいるわけではありません。
ハイライトがいい感じです。
https://github.com/fatih/vim-go

Slack bot を使う準備をしよう

そんなに(bot 自身に)尖った機能をつける気はないので、Apps から Bots の Integration を追加しましょう。

Slack の Workspace で Apps 検索
スクリーンショット 2019-05-30 16.15.55.png

「View App Directory」
スクリーンショット 2019-05-30 16.16.16.png

Bots で検索
スクリーンショット 2019-05-30 16.17.46.png

Add Configurations で追加できます
 .png

名前には日本語は(今は)使えません(前は使えたと思うんだけど・・・)
スクリーンショット 2019-05-30 16.28.39.png

  • 追加完了したら API Token を控えましょう(漏れないよう注意!)
  • emoji とか icon とかいい感じに設定しましょう
  • 説明を入れましょう
    • 雑すぎる説明だと管理者にうっかり消されちゃうかも知れません
  • API Token を利用した実行 IP が固定されてるならついでに IP 制限を設定しておきましょう

Bot で Slack に Hello, World してみよう

API Token さえ手に入ればあとはやりたい放題です。
まずは Slack bot をいい感じに使えるパッケージを入れましょう。
今回使うのはこちらです。
https://github.com/nlopes/slack

※ 同じディレクトリに複数の main() は存在できないので、さっきの hello は消しておきましょう。(ディレクトリを変えるのでも化)

まずは(API をうっかりお漏らししたくないので)他のファイルに書いて、import するようにします。

$ ls
bots.go token
$ ls token/
slack.go
$ cat token/slack.go
package token

const Slack = "INPUT YOUR SLACK TOKEN"  ←ここに書いておく

ついでにいつうっかり git push してもいいように ignore しておきましょう。

$ cat .gitignore
token/*

これでまぁ間違っても漏らさないでしょう。
(git の管理とか Token の管理は、漏洩しなければ好きにしてもらって構いません。もっといい方法をご存知であれば教えてください。)

指定のチャンネルにメッセージをポストしてみます。

bots.go
package main

import (
    "./token"
    "github.com/nlopes/slack"
)

func main() {
    api := slack.New(token.Slack)
    channel := "Input your channel name(or ID)"
    value := "hello, world!"
    api.PostMessage(channel, slack.MsgOptionText(value, false))
}

怒られましたね。

$ go run bots.go
bots.go:5:2: cannot find package "github.com/nlopes/slack" in any of:
    /usr/local/go/src/github.com/nlopes/slack (from $GOROOT)
    /Users/hogehoge/go/src/github.com/nlopes/slack (from $GOPATH)

インストールしていないパッケージについてはこのように怒られます。
慌てず騒がず go get しましょう。

$ go get github.com/nlopes/slack

もう一度。

$ go run bots.go

slack にメッセージが投稿されました :tada:

スクリーンショット 2019-05-30 17.02.32.png

Bot をチャンネルに常駐させて特定のワードに反応させてみよう

※ 先に、ターゲットとなるチャンネルに作成した bot を invite しておいてください。

このへんから Go の良さみを感じられます。

いい感じにコードを書きます。

bots.go
package main

import (
    "./token"
    "github.com/nlopes/slack"
    "log"
    "os"
    "strings"
)

func run(api *slack.Client) int {
    rtm := api.NewRTM()
    go rtm.ManageConnection()

    for {
        msg := <-rtm.IncomingEvents
        log.Printf("MSG: %#v\n", msg.Data)

        switch ev := msg.Data.(type) {
        case *slack.HelloEvent:
            log.Printf("Start up!")

        case *slack.MessageEvent:
            if strings.Contains(ev.Text, "おはよう") {
                text := "Good morning!"
                rtm.SendMessage(rtm.NewOutgoingMessage(text, ev.Channel))
            }
        }
    }
}

func main() {
    api := slack.New(token.Slack)
    os.Exit(run(api))
}

実行します。

$ go run bots.go
2019/05/30 17:51:06 MSG: &slack.ConnectingEvent{Attempt:1, ConnectionCount:0}
2019/05/30 17:51:08 MSG: &slack.ConnectedEvent{ConnectionCount:0, Info:(*slack.Info)(0xc0000)}
2019/05/30 17:51:08 MSG: &slack.HelloEvent{}
2019/05/30 17:51:08 Start up!

特定ワード「おはよう」をツイートつぶやいてみましょう。
スクリーンショット 2019-05-30 17.52.09.png

bot が反応して挨拶してくれました :tada:
これでいくらでも人工無脳が作れますね。
slackbot の1機能を車輪の再開発できました。

ちょっと解説

 13     go rtm.ManageConnection()

ここはいわゆる goroutine というやつですね。
ここから非同期で rtm.ManageConnection() が実行されるので、落ちるまで Slack のコネクションが張ってもらえる感じです。たぶん。

 15     for {
 16         msg := <-rtm.IncomingEvents
 17         log.Printf("MSG: %#v\n", msg.Data)
 18
 19         switch ev := msg.Data.(type) {
 20         case *slack.HelloEvent:
 21             log.Printf("Start up!")
 22
 23         case *slack.MessageEvent:
 24             if strings.Contains(ev.Text, "おはよう") {
 25                 text := "Good morning!"
 26                 rtm.SendMessage(rtm.NewOutgoingMessage(text, ev.Channel))
 27             }
 28         }
 29     }
 30 }

無限ループでイベントを監視し続けています。

 19         switch ev := msg.Data.(type) {
 20         case *slack.HelloEvent:

というふうにして、msg の型に応じて処理を分けられます。
どんなイベントがあるかはソース読むとかなんとかすればわかると思います。たぶん。
https://github.com/nlopes/slack/tree/95b04eeaeb73ff58f430062cd0d39592e03d01ad/slackevents

社内サーバでデーモンとして実行させて常駐させよう

社内サーバがどうなっているかはわからないので、
「Centos デーモン化」
とかそんな感じでググってどうにかしてください。

ただし、Go ではクロスコンパイルが容易にできるので

$ GOOS=linux GOARCH=amd64 go build bots.go
$ ls
bots    bots.go token

とかやるだけで簡単に Linux 用の実行ファイルがシングルバイナリでできちゃいます。
あとはこれ(bots)をサーバに配布して実行するだけ。とっても簡単ですね。

小ネタ

せっかくスラッシュコマンドではなく Bot にしたんだから何か話しかけてる感欲しい!
と思ったときは、MessageEvents の Message の先頭に @bots があるかどうか、みたいな判定をしてトリガーにしています。

 30         case *slack.MessageEvent:
 31             log.Printf("Message: %#v\n", ev)
 32             message := ""
 33
 34             if strings.Contains(ev.Text, isuzu) {

このときの isuzu には Bot の UserID(装飾済み)を記述しています。

 18     isuzu := "<@hogehoge>"

Bot が受け取るメッセージではメンションが上記のように記載されているためです。
Bot の ID 取得するのにも API が使えますので、活用してみてください。

まとめ

Go で bot を作るとサーバに余計なものインストールしないで実行可能なバイナリを作れるので、社内 bot 作るのにとても便利です。
スラッシュコマンドと違って、誰かに使ってもらえてるってのがすごく可視化されるのと、ちょっとした単純なコールアンドレタスポン酢単語へのレスポンスを登録しておくだけで他の人へ挨拶したりして愛着が湧くので、とてもメンテナンスモチベーションが湧きます。
Slack bot おすすめですよ。

2
2
0

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
2