はじめに
Ansible でよくある困りごとのひとつとして、タスクのログに複数行の文字列が含まれるとき、以下のように人間の眼にはやさしくない表示になることが挙げられます。改行がエスケープシーケンスとして表示されるためです。
...
TASK [Referring undefined variable] ********************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an unde
fined variable. The error was: 'undefined_variable' is undefined. 'undefined_var
iable' is undefined\n\nThe error appears to be in '/runner/project/demo.yaml': l
ine 20, column 7, but may\nbe elsewhere in the file depending on the exact synta
x problem.\n\nThe offending line appears to be:\n\n\n - name: Referring undef
ined variable\n ^ here\n"}
...
この対策として、改行が改行として表示されるように 出力を YAML 形式にする 方法がよく知られています。本エントリ公開時点では、次の二つの方法が一般的です。
- Ansible の組み込みの機能を利用する(Ansible 2.13 以降のみ)
ansible.cfg
のcallback_result_format
(または環境変数ANSIBLE_CALLBACK_RESULT_FORMAT
)にyaml
を指定する
- コレクション
community.genral
のコールバックプラグインyaml
を利用するansible.cfg
のstdout_callback
(または環境変数ANSIBLE_STDOUT_CALLBACK
)にcommunity.general.yaml
を指定する
一方で、同じ困りごとは AWX でも発生しますが、AWX で同じ対策を試みても意外と素直にいきません。
先日、これに関する質問が Ansible Community Forum に寄せられ ました。フォーラムでもぼくから回答済みですが、本エントリでは、AWX でジョブのログを YAML 形式で出力させる方法を改めて日本語で簡単に紹介します。
目次
基本的な考え方
うまく構成できれば 前述のどちらの対策も AWX で利用できます が、いずれの場合でも次の点が重要です。
- 利用する EE のイメージ が YAML 形式をサポートできるように正しく構成されていること
- 場合によっては AWX のコントロールプレーンの EE も変更が必要なこと
- ジョブ用の 環境変数または
ansible.cfg
を正しく構成する こと
手順
以下、前述の点を順に紹介します。
(1) 利用する EE イメージを準備する
AWX では、すべてのジョブは例外なく EE 内で処理されます。したがって、そもそもの EE のイメージが YAML 形式での出力に対応している必要があります。
技術的な背景は後述しますが、実施する対策ごとの要件は次の通りです。
callback_result_format
を変更したい場合- Ansible 2.13 以降が導入されていること
- Ansible Runner に含まれるコールバックプラグイン
awx_display
がオプションcallback_result_format
を扱えること
stdout_callback
を変更したい場合- コレクション
community.general
がインストールされていること
- コレクション
Ansible Builder を使ってていねいにビルドしてももちろんよいですが、次のような Dockerfile
をビルドすれば、既成の EE イメージを簡単に修正できます。ここでは quay.io/ansible/awx-ee:latest
をベースに必要な変更を加えています。
FROM quay.io/ansible/awx-ee:latest
# 必須
USER root
# callback_result_format を変更したい場合
## プラグイン awx_display が callback_result_format を扱えるようにソースコードを修正する
RUN sed -i 's/ - default_callback/ - default_callback\n - result_format_callback/g' /usr/local/lib/python3.9/site-packages/ansible_runner/display_callback/callback/awx_display.py
# stdout_callback を変更したい場合
## コレクション community.general をインストールする
RUN ansible-galaxy collection install -p /usr/share/ansible/collections/ansible_collections community.general
# 必須
USER 1000
ビルドしたら、コンテナレジストリにプッシュします。
(2) コントロールプレーンの EE を変更する
AWX のコントロールプレーン(*-task
の Pod)では、プロジェクトの同期などのジョブを実行する EE として *-ee
コンテナが動作しています。このイメージにはデフォルトで quay.io/ansible/awx-ee:latest
が使われますが、以下の場合にはこの変更も必要です。
- プロジェクトの同期のログも YAML 形式にしたい場合
- YAML 形式にする設定を AWX の
Extra Environment Variables
で行う場合(後述)
とくに、community.general.yaml
を利用したい場合は、コントロールプレーンの EE を変更しないとプロジェクトの同期がエラーで失敗するようになるため注意が必要です。
コントロールプレーンの EE イメージを変更するには、AWX Operator でデプロイするカスタムリソース AWX
の spec
に control_plane_ee_image
を追加します。
...
spec:
...
control_plane_ee_image: registry.example.com/ansible/awx-ee:latest-yaml
...
(3) 目的のオプションを変更する
最後に、実際に callback_result_format
または stdout_callback
を変更します。なお、callback_result_format
は環境変数と ansible.cfg
のどちらでも変更できます が、stdout_callback
は環境変数でしか変更できません。
環境変数は Settings
> Job settings
の Extra Environment Variables
で指定できますが、グローバルに変更される点に注意が必要です。細かく制御したい場合はコンテナグループを作って Pod に env
を持たせるほうがよいでしょう。
{
# callback_result_format を変更したい場合
"ANSIBLE_CALLBACK_RESULT_FORMAT": "yaml"
# stdout_callback を変更したい場合
"ANSIBLE_STDOUT_CALLBACK": "community.general.yaml"
}
callback_result_format
は、プロジェクトのルートに次の ansible.cfg
を配置することでも変更できます。
[defaults]
callback_result_format = yaml
結果
AWX でもログが YAML 形式で表示されるようになり、読みやすくなります。
...
TASK [Referring undefined variable] ********************************************
fatal: [localhost]: FAILED! =>
msg: |-
The task includes an option with an undefined variable. The error was:
'undefined_variable' is undefined. 'undefined_variable' is undefined
The error appears to be in '/runner/project/demo.yaml': line 20, column
7, but may be elsewhere in the file depending on the exact syntax
problem.
The offending line appears to be:
- name: Referring undefined variable
^ here
...
技術的な背景
細かい余談です。
callback_result_format
のこと
callback_result_format
は、Ansible 2.13 以降でコールバックプラグイン default
に組み込まれたオプションです。AWX のデフォルトの EE イメージには Ansible 2.15 が導入されているため、素直に考えればこのオプションも使えそうに思えますが、実際には(少なくとも本エントリ公開時点の実装では)前述のようにソースコードをいじらなければ使えません。これを理解するには、以下の点が重要です。
- AWX のジョブは、実際には Ansible Runner 経由で実行されること
- Ansible Runner でプレイブックを実行すると、stdout コールバックプラグインが強制的に
awx_display
に変更されること - 本エントリ公開時点の
awx_display
(Ansible Runner 2.3.4 に同梱のもの)は、オプションcallback_result_format
に対応していないこと
実際、オプション callback_result_format
に yaml
を指定した状態で次のタスクを AWX で実行して設定を確認すると、callback_result_format
はあくまでコールバックプラグイン default
の設定を変更するだけで、awx_display
に対しては何ら影響を与えられていないことがわかります。
- name: Dump stdout configuration
ansible.builtin.debug:
var: configuration
vars:
configuration:
01_stdout_callback__________: "{{ lookup('config', 'DEFAULT_STDOUT_CALLBACK', show_origin=true, errors='ignore') }}"
02_result_format_default____: "{{ lookup('config', 'result_format', plugin_type='callback', plugin_name='default', show_origin=true, errors='ignore') }}"
03_result_format_awx_display: "{{ lookup('config', 'result_format', plugin_type='callback', plugin_name='awx_display', show_origin=true, errors='ignore') }}"
TASK [Dump stdout configuration] ***********************************************
ok: [localhost] => {
"configuration": {
"01_stdout_callback__________": "awx_display"
"02_result_format_default____": "yaml",
"03_result_format_awx_display": "",
}
}
プラグインごとの有効なオプションは、そのプラグインの DOCUMENTATION
の定義で決定されます。awx_display
の実装ではフラグメント default_callback
の取り込みが指定されている ため、一見、コールバックプラグイン default
のオプションである callback_result_format
も読み込まれそうです。
DOCUMENTATION = '''
callback: awx_display
short_description: Playbook event dispatcher for ansible-runner
version_added: "2.0"
description:
- This callback is necessary for ansible-runner to work
type: stdout
extends_documentation_fragment:
- default_callback
requirements:
- Set as stdout in config
'''
しかしながら、Ansible 側の実装では、オプション callback_result_format
の定義は default_callback
ではなく別のフラグメントである result_format_callback
に含まれます。
したがって、本エントリで紹介した前述の手順では、sed
により extends_documentation_fragment
に result_format_callback
を追加しています(参考: ansible/ansible-runner#994)。
DOCUMENTATION = '''
callback: awx_display
short_description: Playbook event dispatcher for ansible-runner
version_added: "2.0"
description:
- This callback is necessary for ansible-runner to work
type: stdout
extends_documentation_fragment:
- default_callback
- result_format_callback
requirements:
- Set as stdout in config
'''
これにより、awx_display
のオプションとして callback_result_format
が指定できるようになります。かつ、awx_display
の 実体 はデフォルトで default
(後述)なので、実際にオプションの通りに出力形式が変更されることになります。
TASK [Dump stdout configuration] ***********************************************
ok: [localhost] =>
configuration:
01_stdout_callback__________: awx_display
02_result_format_default____: yaml
03_result_format_awx_display: yaml
stdout_callback
のこと
Ansible Runner は stdout コールバックプラグインとして強制的に awx_display
を利用しますが、awx_display
自体は もともと指定されていたコールバックプラグインを継承 する形で読み込まれるようになっているため、もともとの指定が無視されるわけではありません。
実装として、Ansible Runner は、環境変数 ANSIBLE_STDOUT_CALLBACK
を強制的に awx_display
に変更する 前 に、もともとの値を ORIGINAL_STDOUT_CALLBACK
に保存 しています(ただし、ansible.cfg
の stdout_callback
ではなく環境変数 ANSIBLE_STDOUT_CALLBACK
しか見ていない点は注意が必要です)。
if self.env.get('ANSIBLE_STDOUT_CALLBACK'):
self.env['ORIGINAL_STDOUT_CALLBACK'] = self.env.get('ANSIBLE_STDOUT_CALLBACK')
self.env['ANSIBLE_STDOUT_CALLBACK'] = 'awx_display'
さらに awx_display
は、環境変数 ORIGINAL_STDOUT_CALLBACK
にしたがって、継承するベースクラスを動的に変更 しています。デフォルトは default
です。
# Dynamically construct base classes for our callback module, to support custom stdout callbacks.
if os.getenv('ORIGINAL_STDOUT_CALLBACK'):
default_stdout_callback = os.getenv('ORIGINAL_STDOUT_CALLBACK')
elif IS_ADHOC:
default_stdout_callback = 'minimal'
else:
default_stdout_callback = 'default'
DefaultCallbackModule = callback_loader.get(default_stdout_callback).__class__
class CallbackModule(DefaultCallbackModule):
'''
Callback module for logging ansible/ansible-playbook events.
'''
CALLBACK_NAME = 'awx_display'
これにより、ユーザは環境変数 ANSIBLE_STDOUT_CALLBACK
を指定すれば awx_display
の実体を変更できる ことになります。
ただし、callback_result_format
の項目で紹介した通り、awx_display
にはコールバックプラグイン default
のオプションの一部しか実装されていないため、独自のオプションを持つコールバックプラグインを指定するとエラーになる 場合があります。強引にどうにかしたい場合は、callback_result_format
を無理やり有効化したように、awx_display
がそのオプションを持てるように修正が必要です。
おわりに
なんというか、ややこしいので、AWX で簡単に設定できるようにしたいですね。まずは Ansible Runner 側に手を入れないとですが。
Thank for sharing. I tried your config and it works!
Do you know how to handle job outputs truncate?
For long job output, I saw it displays ‘…’
Hi, to view truncated logs, not tested well but I think you can click the hostname on the truncated task to open details modal window, or simply download full logs by download button on the upper-right corner.
Have fun!