shellモジュールで途中経過を出力させる
terraformのapplyなど、長時間かかる処理を、Ansibleのshellモジュールで実行すると、Ansibleのログ表示が20分など長時間停止してしまい、エラーが出ていたとしてもその認識に不必要に時間がかかってしまったりする。
あまり美しくない実装でも構わないので、準リアルタイムで出力表示させたい。
試行錯誤の末、以下のようにすることで表示できている。
実装概要
処理をバックグラウンドで実行させ、実行ログはターゲットノード上のファイルに出力させる。
その上で、Ansible Playbookでは、一定時間おきに上のログファイルの内容をAnsibleのログとして出力。
途中経過表示サンプル
tasks
- set_fact:
shell_log: "/tmp/shell.{{ lookup('pipe','date +%Y%m%d%H%M%S') }}.log"
- name: terraform apply -auto-approve
shell: |-
{
set -ex
exec > {{shell_log}} 2>&1
terraform init -no-color
terraform apply -auto-approve -no-color || terraform apply -auto-approve -no-color
echo __END__
} &
poll: 0
- pause:
seconds: 1
- shell: cat {{shell_log}}
register: tail
- loop: "{{ range(tail_times)|list }}"
when: tail is not skipped and tail.stdout_lines|last != '__END__'
shell: |
sleep {{ tail_seconds }}
cat {{shell_log}}
register: tail
vars:
tail_times: 10
tail_seconds: 5
- file:
path: "{{shell_log}}"
state: absent
なお、以下を使う事でAnsible側にもログを残すことが可能。
https://qiita.com/hiroyuki_onodera/items/c36ba00da414d9df7e4e
+
ansible.cfg
[defaults]
verbosity = 1
stdout_callback = debug
この設定により、shellモジュールのみでログへの出力が可能となり、loop対象を1モジュールとできることからinclude_tasksなどで分離することも不要とできる。
途中経過表示サンプル(旧)
30秒おきに実行中のログをansibleのdebugモジュールで表示
tasks
- set_fact:
shell_log: "/tmp/shell.{{ lookup('pipe','date +%Y%m%d%H%M%S') }}.log"
- name: terraform apply -auto-approve
shell: |-
{
set -ex
exec > {{shell_log}} 2>&1
terraform init -no-color
terraform apply -auto-approve -no-color || terraform apply -auto-approve -no-color
echo __END__
} &
poll: 0
- pause:
seconds: 1
- shell: cat {{shell_log}}
register: tail
- include_tasks: tail.yml
loop: "{{ range(tail_times)|list }}"
vars:
tail_times: 60 # この場合、最大 60 回 * 30 秒 = 30分間 監視し、次の処理に進む
tail_seconds: 30
- shell: cat {{shell_log}}
register: tail
- debug: { var: tail.stdout_lines }
- file:
path: "{{shell_log}}"
state: absent
tail.yml
---
- when: tail is not skipped and tail.stdout_lines|last != '__END__'
block:
- pause:
seconds: "{{tail_seconds}}"
- shell: cat {{shell_log}}
register: tail
- debug: { var: tail.stdout_lines }
最終行が __END__ となると、以降はskipされる。
サンプルの制約
- エラー処理は未実装
- 時間切れ処理
- スクリプト実行中にエラーとなった場合の処理 (トラップにて対応可能でしょう)