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

参考: 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.

参考: ソースコードのコメント

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

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

上のように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 — Ansible Documentation

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

参考: [Ansible] 環境変数を取得する ansible_env.hoge と lookup("env", "hoge") の違い

変数に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 — Ansible Documentation

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列で記載(値は折返さない)

参考: Attaching content and links to messages | Slack

サンプルコード

Sample Ansible Playook

P.S. Twitterもやってるのでフォローしていただけると泣いて喜びます:)

@gkzvoice

#gkz