てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] 安全側に倒す ansible.cfg の設定

はじめに

意図しないまま実行を進めないようにするため、ちょっとしたことでもエラーに倒して早めに処理を止める設定の紹介です。インベントリ周りが中心です。

  • ansible.cfg
[defaults]
duplicate_dict_key=error

[inventory]
host_pattern_mismatch=error
any_unparsed_is_failed=True

要件などに合わせて調整は必要かと思いますが、このあたりからベースにすると良いのではないかと思っています。

インベント周りはデフォルトでは結構ゆるい印象があります。

以下詳細(ansible 2.9.23 で確認)です。

YAMLのキーの重複時の挙動の指定(DUPLICATE_YAML_DICT_KEY

DUPLICATE_YAML_DICT_KEY

YAMLのキーの重複時の挙動を指定する。デフォルトは warn で、警告を表示して処理を継続する。

例えば以下の Playbook では、モジュール名である debug が重複している。

---
- hosts: ios
  gather_facts: false

  tasks:
    - name:
      debug:
        msg: msg1
      debug:
        msg: msg2

これを実行すると、警告が表示されるが処理を続ける。後に定義したキーが優先される。

$ ansible-playbook -i inventory.ini test.yml 
[WARNING]: While constructing a mapping from /home/ansible/test.yml, line 10, column 7, found a duplicate dict key (debug). Using last defined value only.

PLAY [ios] ********************************************************************************************************

TASK [debug] ******************************************************************************************************
ok: [ios01] => {
    "msg": "msg2"
}

PLAY RECAP ********************************************************************************************************
ios01                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

$ echo $?
0

キーの重複時にエラーとしたい場合は error を指定する。

[defaults]
duplicate_dict_key=error

この設定で Playbook を実行すると以下のようにエラーとなる。エラーメッセージは分かりにくい。

$ ansible-playbook -i inventory.ini test.yml 
ERROR! Unexpected Exception, this is probably a bug: 'NoneType' object has no attribute 'line'
to see the full traceback, use -vvv
$ echo $?
250

なお、モジュール指定の重複だけでなく、オプションや変数名の重複(同一YAML内)でもエラーになる。

hosts の指定が誤っている場合の挙動の指定(HOST_PATTERN_MISMATCH

HOST_PATTERN_MISMATCH

Playbook の hosts: の指定したホストやグループ名が、インベントリ内に見つからない場合の挙動。デフォルトは warning で、警告を表示するのみ。ansible-playbook コマンドのリターンコードは正常 0 となる。

$ ansible-playbook -i inventory.ini test.yml 
[WARNING]: Could not match supplied host pattern, ignoring: not_existed

PLAY [not_existed] ************************************************************************************************
skipping: no hosts matched

PLAY RECAP ********************************************************************************************************

$ echo $?
0

この場合、Ansible Tower のワークフローとしても正常扱いで次のジョブテンプレートへと進む。

hosts の指定先がインベントリ内に見つからない状況は、その後に想定外の状況を引き起こしかねないので、エラーとして扱って処理を中止した場合もある。特に hosts: "{{ target_host }}" のように変数で指定する場合は、起こりやすい。

エラーとして扱う場合は ansible.cfg で以下のように設定する。defaultsセクションではないので注意。

[inventory]
host_pattern_mismatch=error

以下のように、エラー扱い(リターンコード 1)となる。

$ ansible-playbook -i inventory.ini test.yml 
ERROR! Could not match supplied host pattern, ignoring: not_existed
$ echo $?
1

パースできないインベントリがある場合にエラーとするかの指定(INVENTORY_ANY_UNPARSED_IS_FAILED

INVENTORY_ANY_UNPARSED_IS_FAILED

インベントリファイルの書式の誤りで、正しくパースできないインベントリがある場合にエラーとするかどうかの指定。デフォルトは False で、エラーとしない扱い。

例えば、以下は書式が誤っているインベントリファイル(inventory2.ini)。

[ios2]
ios02 ansible_host=192.168.1.11

# vars とすべきところ var
[ios2:var] 
ansible_network_os=ios
ansible_connection=network_cli

このインベントリを指定して Playbook を実行すると、警告は表示されるがPlaybookの処理は続行しようとする。

$ ansible-playbook -i inventory.ini -i inventory2.ini test.yml 
[WARNING]:  * Failed to parse /home/ansible/inventory2.ini with ini plugin: /home/ansible/inventory2.ini:5: Section [ios:var] has unknown type: var
[WARNING]: Unable to parse /home/ansible/inventory2.ini as an inventory source

PLAY [ios] ********************************************************************************************************

TASK [debug] ******************************************************************************************************
ok: [ios01] => {
    "msg": "Hello Ansible!"
}

PLAY RECAP ********************************************************************************************************
ios01                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

$ echo $?
0

早めにエラーとして処理を中止したい場合は True に設定する。

[inventory]
any_unparsed_is_failed=True

以下のように、Playbookの実行前にエラーで処理が止まる。

$ ansible-playbook -i inventory.ini -i inventory2.ini test.yml 
[WARNING]:  * Failed to parse /home/ansible/inventory2.ini with ini plugin: /home/ansible/inventory2.ini:5: Section [ios:var] has unknown type: var
ERROR! Completely failed to parse inventory source /home/ansible/inventory2.ini
$ echo $?
1

ダイナミックインベントリにも有効。なので、認証情報に誤りがあってインベントリを取得できないときは処理を中止する」という使い方もできる。(aws_ec2 で確認)

補足

似た設定に INVENTORY_UNPARSED_IS_FAILEDもあるが、これは指定されたインベントリのうち1つでもパースできればエラーにしない。 一方、INVENTORY_ANY_UNPARSED_IS_FAILEDは、全てのインベントリがパースできれば正常、1つでもパースできなければエラーとするため、より安全。