Ansibleは強力な構成管理ツールですが、実環境で使ってみようとすると、うまく行かない点がいくつか出てきます。その中には、欲しいモジュールがない、同じことをシェルスクリプトで行うより実行時間が長くなる、などありますが、Playbookのデバッグに手間がかかる、というのもその一つだと思います。
Playbookのデバッグに手間がかかってしまうのには、少なくとも2つ原因があると考えています。1つは、Playbookの実行に失敗したときのエラーメッセージに、デバッグに必要な情報が全て含まれているとは限らないことです。例えば、インベントリやvarsファイルなどで定義した変数、Playbook内でregisterした変数についての情報は出力されません。もう1つは、Playbookの実行にかかる時間です。実環境で使うPlaybookは、実行に数分から数十分かかることがよくあります。Playbookのデバッグでは、より詳細な情報を出力したり、バグ修正の結果を確認したりするたびに、Playbookを時間をかけて実行することになります*1。
このような原因で起きるデバッグの手間を減らせないかと思い、Ansible Playbook向けのデバッガを作ってみました。ソースコードはgithubで公開しています。
ks888/ansible-playbook-debugger · GitHub
以下では、作成したデバッガについて簡単に紹介していきます。
作ったもの
作成したansible-playbook-debuggerは、Ansible Playbook向けのデバッガです。Playbook内のタスクの実行が失敗すると、このデバッガが自動的に起動します。デバッガ内では、各種情報を確認できます。例えば、モジュールの引数、定義した変数、タスクに与えたキーワード(register、whenなど)です。
さらにモジュールの引数を変更し、失敗したタスクを再実行することができます。もし再実行が成功すれば、Playbookの実行は何事もなかったかのように続行されます。
デモ
こんな感じで使えるよーってのを知ってもらうためのデモです。
1つ目は、Playbookの実行 → モジュールの引数ミスによりデバッガ起動 → デバッガ内でモジュールの引数を確認、というデモです。
2つ目は、1つ目からの続きで、誤ったモジュールの引数を削除 → 正しい引数を設定 → 失敗したタスクの再実行 → 成功してPlaybookの続きが実行される、というデモです。
インストール方法
とりあえず使ってみるなら、次の方法でインストールできます。
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でホストを追加したりしている場合、うまくいきません。