てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] ios_config モジュールの backup オプションによるバックアップで意図しないバックアップファイルが削除されるバグについて (Ansible 2.7.5 現在)

■ はじめに

Ansible には Cisco IOS ネットワーク機器に設定変更コマンドを実行する ios_config モジュールがあります。 ios_config モジュールには、backup という、設定変更前のコンフィグを事前に Ansible 側に保存するオプションがあります。 デフォルトは no のため、バックアップは保存しません。backup: yes と指定するとバックアップが有効になります。

この backup オプションによるバックアップには、ターゲットホスト名が類似(例: ios01ios01a)した複数のホストを対象にすると、バックアップファイルが他ホストによって上書きされてしまう、というバグがあります。(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


■ 原因

バックアップする直前に、過去のバックアップファイルを削除します。 削除対象のファイル名を決める際、ホスト名の 前方一致 でマッチさせているため、意図しないホストのバックアップファイルまで消してしまいます。

そのため、例えば ios01aios01 の 2ホスト対してバックアップを行う場合、ios01aios01 の順にのタスクが実行されると、以下のようになってしまいます。

  • 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 のバックアップファイルのみになってしまいました。バグが再現しました。

本来であれば以下のように、 ios01ios01a の 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 で修正されるかもしれません。

参考

対応 issue

github.com

対応 PR

devel ブランチ

github.com

stable-2.7 ブランチ

github.com