■ はじめに
Ansible には Cisco IOS ネットワーク機器に設定変更コマンドを実行する ios_config
モジュールがあります。
ios_config
モジュールには、backup
という、設定変更前のコンフィグを事前に Ansible 側に保存するオプションがあります。
デフォルトは no
のため、バックアップは保存しません。backup: yes
と指定するとバックアップが有効になります。
この backup
オプションによるバックアップには、ターゲットホスト名が類似(例: ios01
と ios01a
)した複数のホストを対象にすると、バックアップファイルが他ホストによって上書きされてしまう、というバグがあります。(Ansible 2.7.5 現在)
現在 devel
ブランチで開発中の Ansible 2.8 では修正されています。
この記事では、本バグについての発生条件、再現性の確認、修正後の動作確認についてご紹介します。
(2019/02/08 追記) Ansible 2.7 は 2.7.7 で本バグが修正されたようです。
Change backup file globbing for network _config modules so backing up one host's config will not delete the backed up config of any host whose hostname is a subset of the first host's hostname (e.g., switch1 and switch11)
ansible/CHANGELOG-v2.7.rst at stable-2.7 · ansible/ansible · GitHub
■ 原因
バックアップする直前に、過去のバックアップファイルを削除します。 削除対象のファイル名を決める際、ホスト名の 前方一致 でマッチさせているため、意図しないホストのバックアップファイルまで消してしまいます。
そのため、例えば ios01a
、ios01
の 2ホスト対してバックアップを行う場合、ios01a
、ios01
の順にのタスクが実行されると、以下のようになってしまいます。
ios01a
のタスクios01a
の前方一致でマッチしたファイルを削除(特に問題なし)ios01a
のバックアップファイルを保存する
ios01
のタスクios01
の前方一致でマッチしたファイルを削除(先程保存したios01a
のバックアプファイルが削除されてしまう)ios01
のバックアップファイルを保存する
■ 再現の確認(Ansible 2.7.5)
バグが発生することを確認してみます。
インベントリファイル (inventory.ini
)
先程例に示した、2ホストを定義して、グループ ios
でまとめます。
[ios] ios01 ansible_host=ios-xe-mgmt.cisco.com ios01a ansible_host=ios-xe-mgmt.cisco.com
変数ファイル (gorup_vars/ios.yml
)
グループ ios
が利用する変数を定義します。特に今回のバグに関係するものはありません。
ansible_network_os: ios ansible_user: user ansible_password: pass9999 ansible_connection: network_cli
playbook (backup_test.yml
)
グループ ios
を対象にして ios_config
モジュールの backup
オプションによる、バックアップのみ行う Playbook にします。
- hosts: ios gather_facts: no tasks: - name: backup test ios_config: backup: yes
実行結果
ここでは分かりやすいように、ホストごとに ansible-playbook
コマンドを分けて実行します。
1つめのホスト(ios01a
)
まずは、ios01a
に対して実行します。
$ ansible --version ansible 2.7.5 (...略...) $ ansible-playbook -i inventory.ini backup_test.yml -l ios01a PLAY [ios] ************************************************************************* TASK [backup test] ***************************************************************** ok: [ios01a] PLAY RECAP ************************************************************************* ios01a : ok=1 changed=0 unreachable=0 failed=0
バックアップファイルは backup
ディレクトリの中に保存される(なければ作成される)ので、backup
ディレクトリ内を確認します。
$ tree backup └── ios01a_config.2018-12-22@10:37:25
正常に、ios01a
のバックアップファイルが保存されました。
2つめのホスト (ios01
)
続いて、ios01
に対して実行します。
$ ansible-playbook -i inventory.ini backup_test.yml -l ios01 PLAY [ios] ************************************************************************* TASK [backup test] ***************************************************************** ok: [ios01] PLAY RECAP ************************************************************************* ios01 : ok=1 changed=0 unreachable=0 failed=0
先ほどと同じく、backup
ディレクトリを確認します。
$ tree backup backup └── ios01_config.2018-12-22@10:38:26
このように、1つめのホスト ios01a
のバックアップファイルが消えてしまい、ios01
のバックアップファイルのみになってしまいました。バグが再現しました。
本来であれば以下のように、 ios01
、ios01a
の 2ホスト分のバックアップアップファイルがあるべきところです。
$tree backup backup ├── ios01_config.2018-12-22@10:38:26 └── ios01a_config.2018-12-22@10:37:25 # このファイルが消えてしまった
■ 開発中の Ansible 2.8 での修正確認
本バグの修正コードは、devel ブランチ(開発中のAnsible 2.8)にマージされています。修正されていることを確認するために、実際に試してみます。
先程用意したインベントリファイルや Playbook など一式はそのまま利用します。backup
ディレクトリは一旦削除しておきます。
1つめのホスト(ios01a
)
まずは、ios01a
に対して実行します。
$ ansible --version ansible 2.8.0.dev0 (...略...) $ ansible-playbook -i inventory.ini backup_test.yml -l ios01a PLAY [ios] ************************************************************************* TASK [backup test] ***************************************************************** ok: [ios01a] PLAY RECAP ************************************************************************* ios01a : ok=1 changed=0 unreachable=0 failed=0 skipped=0
backup
ディレクトリを確認します。
$ tree backup backup └── ios01a_config.2018-12-22@10:51:28
正常に ios01a
のバックアップファイルが保存されました。ここまでは、Ansible 2.7.5 で試したときと同じです。
2つめのホスト(ios01
)
続いて、ios01
に対して実行します。
$ ansible-playbook -i inventory.ini backup_test.yml -l ios01 PLAY [ios] ************************************************************************* TASK [backup test] ***************************************************************** ok: [ios01] PLAY RECAP ************************************************************************* ios01 : ok=1 changed=0 unreachable=0 failed=0 skipped=0
backup
ディレクトリを確認します。
$tree backup backup ├── ios01_config.2018-12-22@10:52:35 └── ios01a_config.2018-12-22@10:51:28
今回(開発中の Ansible 2.8)は、無事に 2つのホスト分のバックアップファイルがある状態になりました。
■ IOS 以外のモジュールにも同様のバグ
修正のPRを確認すると分かりやすいのですが、他のプラットフォームのモジュールにも同じような、ホスト名の前方一致で削除対象のファイル名を決めている箇所があったようです。
junos_config
モジュールの backup
オプションだけ試したのですが、やはり Ansible 2.7.5 で同じバグが再現でき、開発中の Ansible 2.8 で修正されていることを確認しました。
■ まとめ
Ansible 2.7.5 現在、cisco_ios
モジュールの backup
オプションのコンフィグファイルのバックアップの処理で、ターゲットホスト名が類似していると、意図せずファイルが削除される場合があることを確認できました。
このバグは Ansible 2.8 で修正される予定です。また、Ansible 2.7 系のブランチにもバックポートされそう(2018/12/22現在)なので、Ansible 2.7.6 で修正されるかもしれません。