この記事はニフティグループ Advent Calendar 2019の3日目の記事です。
昨日は @johnFkennedy さんで「teachablemachineを使って、なんかやってみた。」でした。コードなしで分類タスクを解けるのは魅力的ですね。
はじめに
この記事ではAWX上で実行した結果をカスタマイズしてslackに通知することをゴールとしています。
多人数でAnsibleを使う場合にはGUI上でタスクの実行、結果の確認ができるAWXが便利です。
AWXを管理する側としては誰が、いつ、どんなタスクを実行して、結果はどうだったのかを通知してもらいたいですよね。
そこで、実行結果を投げる設定をAWXのnotification_template
で行い、slack上でいい感じの通知をしてもらいます。
※slackへの通知はwebhook経由で行います。通知設定はこちらの記事などを参考に各自行ってください。AWXとの連携にはこちらの記事が参考になると思います
以下の作業はすべて通知
の管理者権限を持っているものとします。
環境
_______________
< AWX 8.0.0.0 >
---------------
\ ^__^
\ (oo)\_______
(__) A )\/\
||----w |
|| ||
Ansible 2.8.6
カスタムメッセージの追加方法
以上でカスタムメッセージの追加は完了です
しかし、このままだとテンプレートを実行してもジョブが成功しても失敗しても以下のような無機質なメッセージしか流れません。
Job #3 'Demo Job Template' running: https://towerhost/#/jobs/playbook/3
これを温かみのあるものへと変更していきます。
メッセージのカスタマイズ
カスタムメッセージで使用できる変数
通知にはいつ、誰が、どのプレイブックを実行したか、などの情報が必要です。これらの情報はジョブ実行時にAnsible変数に格納され、流れていきます。
格納される変数のリストはAnsible Tower Documentationに記載されています。1
この変数を参照することで、各種ジョブの状態を確認することができます。
カスタムメッセージで変数を参照する場合には基本、{{ job.<使いたい変数> }}
の形で記述していきます。
例えば、テンプレートの起動者をメッセージに追加する場合には{{ job.summary_fields.created_by.username }}
と記述します。
具体的にどんな値が格納されているのか知りたいときには、一度{{ job }}
のみを記述して、通知を流してみるのが良いです。
sample job templateを実行すると以下のようなjsonが返ってきます。
(折りたたみ)`{{ job }}`で流れてくる内容
{
"id": 17,
"type": "job",
"url": "/api/v2/jobs/17/",
"created": datetime.datetime(2019, 11, 5, 4, 46, 2, 551213, tzinfo=),
"modified": datetime.datetime(2019, 11, 5, 4, 46, 16, 849290, tzinfo=),
"name": "Demo Job Template",
"description": "",
"job_type": "run",
"playbook": "hello_world.yml",
"forks": 0,
"limit": "",
"verbosity": 0,
"job_tags": "",
"force_handlers": False,
"skip_tags": "",
"start_at_task": "",
"timeout": 0,
"use_fact_cache": False,
"launch_type": "manual",
"status": "running",
"failed": False,
"started": "2019-11-05T04:46:16.912606Z",
"finished": None,
"elapsed": 0.148594,
"job_explanation": "",
"execution_node": "awx",
"controller_node": "",
"allow_simultaneous": False,
"scm_revision": "",
"diff_mode": False,
"job_slice_number": 0,
"job_slice_count": 1,
"summary_fields": {
"inventory": {
"id": 1, "name": "Demo Inventory",
"description": "",
"has_active_failures": False,
"total_hosts": 1,
"hosts_with_active_failures": 0,
"total_groups": 0,
"groups_with_active_failures": 0,
"has_inventory_sources": False,
"total_inventory_sources": 0,
"inventory_sources_with_failures": 0,
"organization_id": 1,
"kind": ""
},
"project": {
"id": 6,
"name": "Demo Project",
"description": "",
"status": "successful",
"scm_type": "git"
},
"job_template": {
"id": 7,
"name": "Demo Job Template",
"description": ""
},
"unified_job_template": {
"id": 7,
"name": "Demo Job Template",
"description": "",
"unified_job_type": "job"
},
"instance_group": {
"name": "tower",
"id": 1
},
"created_by": {
"id": 1,
"username": "admin",
"first_name": "",
"last_name": ""
},
"labels": {
"count": 0,
"results": []
}
}
}
jinja2 テンプレート
記述方法から気づく方もいらっしゃるかと思いますが、カスタムメッセージの変数はjinja2 テンプレートで記述します。
これにより、変数から得られる文字を自由に書き換えることが可能です。
例えば、{{ job.started }}
はUTCだったり秒以下小数点が並んでいたりと見づらいです。
そこで、次のように書くことで、日本標準時に直すことができます。
"{{ job.started.split('T')[0] }} {{ job.started.split('T')[-1].split(':')[0] | int + 9 }}:{{ job.started.split('.')[0].split(':')[1:] | join(':') }}"
※{{ job.finished }}
はなぜかはじめにstring
への変換が必要でした。
"{% set f=job.finished ~ '' %} {{ f.split('T')[0] }} {{ f.split('T')[-1].split(':')[0] | int + 9 }}:{{ f.split('.')[0].split(':')[1:] | join(':') }}"
slack投稿のカスタマイズ
webhook経由でのslack通知の場合には、ペイロードをjsonで記述することができます。つまり、投稿するメッセージのフォーマットをある程度いじることができます。
slackへ投げるjsonの形式はslack Formatting messagesを参考にしてください。
slack Message Builderで記述した内容のチェックができて便利です。
以下通知に設定した内容になります。
START MESSAGE BODY
{
"channel": "#test_notification",
"username": "AnsibleNotice",
"text": "{{ job.summary_fields.created_by.username }} が {{ job.name }} を開始しました",
"icon_emoji": ":passport_control:"
}
SUCCESS MESSAGE BODY
{
"channel": "#test_notification",
"username": "AnsibleNotice",
"attachments": [
{
"fallback": "{{ job.name }} is {{ job.status }}",
"color": "good",
"author_name": "{{ job.summary_fields.created_by.username }}",
"title": "{{ job.name }}",
"title_link": "{{ url }}",
"pretext": "{{ job.summary_fields.created_by.username }} が {{ job.name }} を {{ job.status }} で終了しました",
"fields": [
{
"title": "started",
"value": "{{ job.started.split('T')[0] }} {{ job.started.split('T')[-1].split(':')[0] | int + 9 }}:{{ job.started.split('.')[0].split(':')[1:] | join(':') }}",
"short": "true"
},
{
"title": "finished",
"value": "{% set f=job.finished ~ '' %} {{ f.split('T')[0] }} {{ f.split('T')[-1].split(':')[0] | int + 9 }}:{{ f.split('.')[0].split(':')[1:] | join(':') }}",
"short": "true"
},
{
"title": "project",
"value": "{{ job.summary_fields.project.name }}",
"short": "true"
},
{
"title": "inventory",
"value": "{{ job.summary_fields.inventory.name }}",
"short": "true"
},
{
"title": "job_template",
"value": "{{ job.summary_fields.job_template.name }}",
"short": "true"
},
{
"title": "instance_group",
"value": "{{ job.summary_fields.instance_group.name }}",
"short": "true"
},
{
"title": "playbook",
"value": "{{ job.playbook }}",
"short": "true"
}
],
"footer": "AWX Notification"
}
],
"icon_emoji": ":passport_control:"
}
ERROR MESSAGE BODY
{
"channel": "#test_notification",
"username": "AnsibleNotice",
"attachments": [
{
"fallback": "{{ job.name }} is {{ job.status }}",
"color": "danger",
"author_name": "{{ job.summary_fields.created_by.username }}",
"title": "{{ job.name }}",
"title_link": "{{ url }}",
"pretext": "{{ job.summary_fields.created_by.username }} が {{ job.name }} を {{ job.status }} で終了しました",
"fields": [
{
"title": "started",
"value": "{{ job.started.split('T')[0] }} {{ job.started.split('T')[-1].split(':')[0] | int + 9 }}:{{ job.started.split('.')[0].split(':')[1:] | join(':') }}",
"short": "true"
},
{
"title": "finished",
"value": "{% set f=job.finished ~ '' %} {{ f.split('T')[0] }} {{ f.split('T')[-1].split(':')[0] | int + 9 }}:{{ f.split('.')[0].split(':')[1:] | join(':') }}",
"short": "true"
},
{
"title": "project",
"value": "{{ job.summary_fields.project.name }}",
"short": "true"
},
{
"title": "inventory",
"value": "{{ job.summary_fields.inventory.name }}",
"short": "true"
},
{
"title": "job_template",
"value": "{{ job.summary_fields.job_template.name }}",
"short": "true"
},
{
"title": "instance_group",
"value": "{{ job.summary_fields.instance_group.name }}",
"short": "true"
},
{
"title": "playbook",
"value": "{{ job.playbook }}",
"short": "true"
}
],
"footer": "AWX Notification"
}
],
"icon_emoji": ":passport_control:"
}
あとがき
AWXから送信される通知を無機質なものから、温かみのあるものへと変更しました。通知を見るたびに柔らかなbotらしさを感じることができます。
皆様もよいAWXライフを送ってください。
-
11/13のVersion 3.6.0 updateに伴って、Tower Documentationにvariablesについての記述が追加されました。 ↩