Ansibleのslackモジュールを使う際に必要な"token"でハマった話他[token/トークンの取り扱いと変数のdefault値など]

## はじめに
Ansibleのslackモジュールでslackに通知する際、トークン(token)の設定でエラーを引きました。
本記事では、エラーの内容とそのトラブルシュートを共有します。

## 環境/バージョン情報
- Ubuntu19.04 (Disco Dingo)(ローカル)
- ansible 2.9.1
  - python version = 2.7.16 (default, Oct  7 2019, 17:36:04) [GCC 8.3.0]


## エラーメッセージ
トークンの値が誤っていることを指摘するものでした。

```
TASK [Use the attachments API] **********************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Slack has updated its webhook API.  You need to specify a token of the form XXXX/YYYY/ZZZZ in your playbook"}

```
※ここで使っていたtokenはslackでbotを作る際に生成されるxoxbから始まる文字列です。

```
gkz@localhost ~$ tail ~/.bashrc | grep SLACKBOT_TOKEN
export SLACKBOT_TOKEN='xoxb-xxx'

```

## 正しいトークン
slackのincoming webhook urlのservices/から後ろの**xxxx/yyyy/zzzz**です。

**https://hooks.slack.com/services/xxxx/yyyy/zzzz**

```
gkz@localhost ~$ cat ~/.bashrc | grep SLACKFORMAT
export INCOMING_WEBHOOK_URL_SLACKFORMAT='xxxx/yyyy/zzzz'

```

※incoming webhook urlの取得場所
https://api.slack.com/apps/${APP_ID}/incoming-webhooks
![Screenshot from 2019-11-20 01-09-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/341653/cd6f4697-46c7-fa4e-865b-5a160337b369.png)


参考: redditのQA
>You need to copy token from webhook url (open webhook settings and you will see it). In fact, token is just part of url 

[Slack Usage with Ansible? Token error etc.](https://www.reddit.com/r/ansible/comments/5imq0t/slack_usage_with_ansible_token_error_etc/)



参考: ソースコードのコメント
>token:
 description:
 - Slack integration token.  (前略) In 1.8 and above, ansible adapts to the new slack API where tokens look like C(G922VJP24/D921DW937/3Ffe373sfhRE6y42Fg3rvf4GlK).  (中略) Please keep in mind the tokens are not the API tokens but are the webhook tokens. 

[ansible/slack.py at devel · ansible/ansible]
(https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/notification/slack.py)


無事、Ansibleのplay-bookからslackにメッセージを送信することが出来ました。

![Screenshot from 2019-11-20 02-37-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/341653/2742901b-e3c1-10d1-be77-a8e102de0b71.png)



上のようにslackにスマートなメッセージを送るまでに苦労した点がいくつかあったので、小話として取り上げます。
- token/トークンは環境変数として取り扱う
- 変数にdefault値を採用
- attachmentsのオプションのshortがFalseである場合、titleとvalueひとつひとつは折り返さない

playbookはこんなかんじです。↓↓

```
---
- hosts: all
  connection: local
  gather_facts: no
  become: no

  tasks:
    - shell: ping -c 5 -w 5 localhost
      register: result_shell
      failed_when: >
          ("No such file or directory" in result_shell.stdout) or
          (result_shell.stderr != '') or
          (result_shell.rc == 10)
      changed_when: false

    - name: debug result_shell.stdout
      debug:
        msg: "{{ result_shell.stdout | default('None', true) }}"
    - name: debug result_shell.stderr
      debug:
        msg: "{{ result_shell.stderr | default('None', true) }}"

    - name: Use the attachments API
      slack:
        username: "{{ lookup('env', 'SLACKBOT_NAME') | default('ansibleBot')  }}"
        token: "{{ lookup('env', 'INCOMING_WEBHOOK_URL_SLACKFORMAT') }}"
        channel: "{{ lookup('env', 'DST_CHANNEL') }}"
        attachments:
          - title: Display Result Ping Communicate
            text: "{{ inventory_hostname }}"
            color: "#ff00dd"
            fields:
              - title: "[STDOUT] Ping Communicate"
                value: "{{ result_shell.stdout | default('None', true)}}"
                #short: True
                short: False
              - title: "[STDERR] Ping Communicate"
                value: "{{ result_shell.stderr | default('None', true)}}"
                #short: True
                short: False

```

## token/トークンは環境変数として取り扱う
tokenや投稿先などホスト(Ansibleサーバー)で指定する値やplaybookに公開したくない値は環境変数で渡すのがベターではないかと思います。


```
username: "{{ lookup('env', 'SLACKBOT_NAME') }}"
```

参考: [env – read the value of environment variables &mdash; Ansible Documentation]
(https://docs.ansible.com/ansible/latest/plugins/lookup/env.html)

※環境変数の参照先がホスト(Ansibleサーバー)ではなくターゲット(Ansibleの設定先)である場合、**ansible_env**を使えばよさそうです。


参考: [[Ansible] 環境変数を取得する ansible_env.hoge と lookup("env", "hoge") の違い](https://tekunabe.hatenablog.jp/entry/2019/03/09/ansible_env)


## 変数にdefault値を採用
変数にdefault値を採用することができますが、trueと書く必要があるとそうではないケースがあります。

- 変数が**未定義の場合**、default(hogehoge)とtrueは不要
 - ユースケース: Ansibleサーバーで環境変数として定義されているか確認できない場合

```
username: "{{ lookup('env', 'SLACKBOT_NAME') | default('ansibleBot')  }}"
```
- **定義された**変数の値がカラ、Falseである場合、default('hogehoge', true)とtrueは必要
  - ユースケース: デバッグする値がカラであるときにカラであると明示する場合

```
fields:
    - title: "[STDERR] Ping Communicate"
      value: "{{ result_shell.stderr | default('None', true)}}"
      #short: True
      short: False
```

参考: [Filters &mdash; Ansible Documentation]
(https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html)


## attachmentsのオプションのshortがFalseである場合、titleとvalueひとつひとつは折り返さない

```
    - name: Use the attachments API
      slack:
        username: "{{ lookup('env', 'SLACKBOT_NAME') }}"
        token: "{{ lookup('env', 'INCOMING_WEBHOOK_URL_SLACKFORMAT') }}"
        channel: "{{ lookup('env', 'DST_CHANNEL') }}"
        attachments
          - title: Display Result Ping Communicate
            text: "{{ inventory_hostname }}"
            color: "#ff00dd"
            fields:
              - title: "[STDOUT] Ping Communicate"
                value: "{{ result_shell.stdout | default('None', True)}}"
                short: True
                #short: False
              - title: "[STDERR] Ping Communicate"
                value: "{{ result_shell.stderr | default('None', True)}}"
                short: True             ##title/valueで定義された値は複数列で記載(値は折返す)
                #short: False　         ##title/valueで定義された値は1列で記載(値は折返さない)

```

![Screenshot from 2019-11-20 02-40-41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/341653/2f802997-cb45-ad0c-5cad-b2ef2a5129df.png)

参考: [Attaching content and links to messages | Slack](https://api.slack.com/docs/message-attachments)

## サンプルコード
[Sample Ansible Playook](https://github.com/gkzz/ansible-sample)

## P.S. Twitterもやってるのでフォローしていただけると泣いて喜びます:)
[@gkzvoice](https://twitter.com/gkzvoice)


[#gkz](https://twitter.com/hashtag/gkz)