Ansible Playbook向けのデバッガを作りました

(追記:このページの情報は若干古くなっています。Qiitaに紹介記事がありますので、参考にして下さい)

Ansibleは強力な構成管理ツールですが、実環境で使ってみようとすると、うまく行かない点がいくつか出てきます。その中には、欲しいモジュールがない、同じことをシェルスクリプトで行うより実行時間が長くなる、などありますが、Playbookのデバッグに手間がかかる、というのもその一つだと思います。

Playbookのデバッグに手間がかかってしまうのには、少なくとも2つ原因があると考えています。1つは、Playbookの実行に失敗したときのエラーメッセージに、デバッグに必要な情報が全て含まれているとは限らないことです。例えば、インベントリやvarsファイルなどで定義した変数、Playbook内でregisterした変数についての情報は出力されません。もう1つは、Playbookの実行にかかる時間です。実環境で使うPlaybookは、実行に数分から数十分かかることがよくあります。Playbookのデバッグでは、より詳細な情報を出力したり、バグ修正の結果を確認したりするたびに、Playbookを時間をかけて実行することになります*1

このような原因で起きるデバッグの手間を減らせないかと思い、Ansible Playbook向けのデバッガを作ってみました。ソースコードgithubで公開しています。

GitHub - ks888/ansible-playbook-debugger: A Debugger for Ansible Playbook

以下では、作成したデバッガについて簡単に紹介していきます。

作ったもの

作成したansible-playbook-debuggerは、Ansible Playbook向けのデバッガです。Playbook内のタスクの実行が失敗すると、このデバッガが自動的に起動します。デバッガ内では、各種情報を確認できます。例えば、モジュールの引数、定義した変数、タスクに与えたキーワード(register、whenなど)です。

さらにモジュールの引数を変更し、失敗したタスクを再実行することができます。もし再実行が成功すれば、Playbookの実行は何事もなかったかのように続行されます。

デモ

こんな感じで使えるよーってのを知ってもらうためのデモです。

1つ目は、Playbookの実行 → モジュールの引数ミスによりデバッガ起動 → デバッガ内でモジュールの引数を確認、というデモです。

Demo 1

2つ目は、1つ目からの続きで、誤ったモジュールの引数を削除 → 正しい引数を設定 → 失敗したタスクの再実行 → 成功してPlaybookの続きが実行される、というデモです。

Demo 2

インストール方法

とりあえず使ってみるなら、次の方法でインストールできます。

pip install ansible-playbook-debugger 

ソースも見てみるなら、次の方法でインストールできます。

git clone https://github.com/ks888/ansible-playbook-debugger
pip install -e ./ansible-playbook-debugger

使い方

このデバッガは簡単に使い始めることができます。ansible-playbookコマンドを呼ぶ代わりに、ansible-playbook-debuggerコマンドを呼ぶようにするだけです。ansible-playbook-debuggerコマンドは、Playbookの失敗時にデバッガが起動するようにセットアップした上で、内部でansible-playbookコマンドを呼び出します。

ansible-playbookコマンドのオプションは、ansible-playbook-debuggerコマンドでも使えます。ただし、複数ホストに対してAnsibleで設定をする場合、デバッガの多重起動を防ぐために、--forks=1をオプションに与える必要があります。

デバッガ起動後は、コマンドを通して引数の確認や変更ができます。例えば、printコマンドでは、モジュール引数や変数の確認ができます。また、setコマンドでは、モジュール引数の設定ができます。さらにredoコマンドでは、タスクの再実行ができます(全コマンドのリストと説明は、githubを参照して下さい)。

以下に、デバッガの使用例を2つ挙げます。

例1:モジュール引数の確認と設定

上記のデモと同じく、モジュール引数の確認、設定、タスクの再実行をしています。(Apdb)で始まる行が、デバッガのコマンドを入力した行です。

~/src/ansible-playbook-debugger-demo% cat demo1.yml 
---
- hosts: local
  gather_facts: no
  tasks:
    - name: ping with invalid module arg
      ping: invalid_args=v

    - name: ping again
      ping:

~/src/ansible-playbook-debugger-demo% cat inventory 
[local]
testhost ansible_ssh_host=127.0.0.1 ansible_connection=local

~/src/ansible-playbook-debugger-demo% ansible-playbook-debugger -i inventory demo1.yml -vv      

PLAY [local] ****************************************************************** 

TASK: [ping with invalid module arg] ****************************************** 
<127.0.0.1> REMOTE_MODULE ping invalid_args=v
The task execution failed.
reason: the task returned with a "failed" flag
result: {u'msg': u'unsupported parameter for module: invalid_args', u'failed': True}

Now a playbook debugger is running...
(Apdb) print module_args
module_args: invalid_args=v
(Apdb) del module_args invalid_args
deleted
(Apdb) print module_args
module_args: 
(Apdb) set module_args data v
updated: data=v
(Apdb) print module_args
module_args: data=v
(Apdb) redo
<127.0.0.1> REMOTE_MODULE ping data=v
ok: [testhost] => {"changed": false, "ping": "v"}

TASK: [ping again] ************************************************************ 
<127.0.0.1> REMOTE_MODULE ping
ok: [testhost] => {"changed": false, "ping": "pong"}

PLAY RECAP ******************************************************************** 
testhost                   : ok=2    changed=0    unreachable=0    failed=0   

~/src/ansible-playbook-debugger-demo% 

例2:各種情報の確認

変数、キーワード、ホスト情報などの各種情報を確認しています。listコマンドで実行したタスクについての情報の確認、printコマンド(引数なし)でモジュールの引数、変数、キーワードなどの確認、errorコマンドでエラー情報の確認をしています。最後はCtrl-dでデバッガを終了しています。

~/src/ansible-playbook-debugger-demo% cat demo2.yml 
---
- hosts: local
  gather_facts: no
  tasks:
    - name: ping with invalid module arg
      ping:
      args:
        k: v

    - name: ping again
      ping:

~/src/ansible-playbook-debugger-demo% ansible-playbook-debugger -i inventory demo2.yml -vv

PLAY [local] ****************************************************************** 

TASK: [ping with invalid module arg] ****************************************** 
<127.0.0.1> REMOTE_MODULE ping k=v
The task execution failed.
reason: the task returned with a "failed" flag
result: {u'msg': u'unsupported parameter for module: k', u'failed': True}

Now a playbook debugger is running...
(Apdb) list
module name     : ping
module args     : 
complex args    : {'k': 'v'}
keyword         : register:None, delegate_to:None, ignore_errors:False, environment:{}, changed_when:None, failed_when:None, always_run:False
hostname        : testhost
groups          : local
connection type : local
(Apdb) print
module_name: ping
module_args: 
complex_args: {'k': 'v'}
delegate_to: None
failed_when: None
vars: {'delegate_to': None, 'failed_when': None, 'changed_when': None, 'playbook_dir': '.', 'register': None, 'inventory_dir': '/home/yagami/src/ansible-playbook-debugger-demo', 'always_run': False, 'role_names': [], 'play_hosts': ['testhost'], 'ignore_errors': False}
ansible_connection: local
environment: {}
inventory_hostname: testhost
playbook_dir: .
ansible_ssh_host: 127.0.0.1
hostvars: {'testhost': {}}
group_names: ['local']
inventory_file: inventory
always_run: False
groups: {'ungrouped': [], 'all': ['testhost'], 'local': ['testhost']}
ignore_errors: False
changed_when: None
inventory_hostname_short: testhost
register: None
inventory_dir: /home/yagami/src/ansible-playbook-debugger-demo
ansible_ssh_user: yagami
defaults: {}
role_names: []
play_hosts: ['testhost']
(Apdb) error
reason: the task returned with a "failed" flag
result: {u'msg': u'unsupported parameter for module: k', u'failed': True}
(Apdb) 
failed: [testhost] => {"failed": true}
msg: unsupported parameter for module: k

FATAL: all hosts have already failed -- aborting

PLAY RECAP ******************************************************************** 
           to retry, use: --limit @/home/yagami/demo2.retry

testhost                   : ok=0    changed=0    unreachable=0    failed=1   

~/src/ansible-playbook-debugger-demo% 

まとめ

作成したAnsible Playbook向けのデバッガについて、概要、デモ、インストール方法、使い方を紹介をしました。Ansibleによる構成管理に役立つと思いますので、ぜひ使ってみて下さい。

*1:--start-at-taskオプションを使えば、任意のタスクからPlaybookを実行できますが、registerで変数を追加したり、add_hostでホストを追加したりしている場合、うまくいきません。