●はじめに
Ansibleの Cisco IOS の設定変更に対応するモジュール「ios_config」にはコンフィグを指定するオプションが複数あります。
lines
はメイン処理、parents
は「interface Gi1/0/1」などの階層指定、before
は事前処理、after
は事後処理といった具合です。
このうち、lines
とparents
について
「lines
にinterfaceコマンド指定しても特に困らなそうだけど、parents
とどう使い分けたらよいのだろう」
という疑問があったため動作検証して挙動を探りました。環境はansible 2.1です。(一部はモジュールのソースも確認)
個人的な結論としては「interfaceコマンドのような階層指定ははフルスペルでparents
に指定するのが良い」と思っています。
●パターン別検証
以下の条件を組み合わせて4パターン検証しました。
- interfaceコマンドを
parents
に指定するか、lines
に指定するか - interfaceコマンドを「interface」のようにフルスペルで指定するか、「int」のように省略するか
事前のコンフィグは以下の通りです。
interface GigabitEthernet1/0/1
switchport access vlan 192
switchport mode access
end
このインターフェースに対してlines
でdescription を指定し、Playbookを2回実行して冪等性含めて検証します。
【パターン1】parents にフルスペルで指定する
Playbookの内容
---
- hosts: cisco # インベントリファイルで 192.168.1.1(とりあえず1台)を[cisco]グループで定義済み
gather_facts: no
connection: local
tasks:
- name : set description
ios_config:
parents: # parents にフルスペルで指定
- int interface GigabitEthernet1/0/1
lines:
- description TESTTESTTEST
provider: "{{ cli }}"
notify: save config # 変更があったら以下で定義するhandler「save config」を呼び出す
register: result
- name: DEBUG # debug表示
debug: var=result
handlers:
- name: save config # コンフィグを保存する
ios_command:
commands:
- write memory
provider: "{{ cli }}"
register: result
- name: DEBUG # debug表示
debug: var=result
vars:
cli: # 認証情報を定義しておく
host: "{{ inventory_hostname }}"
username: "{{ ansible_user }}"
password: "{{ ansible_password }}"
authorize: true
auth_pass: "{{ cisco_enable_secret }}"
Plyaybooの実行(1回目)
user@ubuntu-vm:/etc/ansible$ ansible-playbook cat_int.yml
PLAY [cisco] *******************************************************************
TASK [set description] *********************************************************
changed: [192.168.1.1]
TASK [DEBUG] *******************************************************************
ok: [192.168.1.1] => {
"result": {
"changed": true,
"responses": [
"",
""
],
"updates": [
"interface GigabitEthernet1/0/1",
"description TESTTESTTEST"
]
}
}
RUNNING HANDLER [save config] **************************************************
ok: [192.168.1.1]
PLAY RECAP *********************************************************************
192.168.1.1 : ok=3 changed=1 unreachable=0 failed=0
無事にdescriptionが設定されました。
interface GigabitEthernet1/0/1
description TESTTESTTEST
switchport access vlan 192
switchport mode access
end
Plyaybookの実行(2回目)
user@ubuntu-vm:/etc/ansible$ ansible-playbook cat_int.yml
PLAY [cisco] *******************************************************************
TASK [set description] *********************************************************
ok: [192.168.1.1]
TASK [DEBUG] *******************************************************************
ok: [192.168.1.1] => {
"result": {
"changed": false,
"updates": []
}
}
PLAY RECAP *********************************************************************
192.168.1.1 : ok=2 changed=0 unreachable=0 failed=0
2貝目は変更なしとみなされ、descriptionコマンドは実行されなかったかたちとなります。
冪等性があるといえます。
【パターン2】parents に省略して指定する
Playbookの内容
抜粋です。他はパターン1と同じです。
ios_config:
parents: # parents に省略して指定
- int gi1/0/1
lines:
- description TESTTESTTEST
Plyaybooの実行(1回目)
user@ubuntu-vm:/etc/ansible$ ansible-playbook cat_int.yml
PLAY [cisco] *******************************************************************
TASK [set description] *********************************************************
changed: [192.168.1.1]
TASK [DEBUG] *******************************************************************
ok: [192.168.1.1] => {
"result": {
"changed": true,
"responses": [
"",
""
],
"updates": [
"int gi1/0/1",
"description TESTTESTTEST"
]
}
}
RUNNING HANDLER [save config] **************************************************
ok: [192.168.1.1]
PLAY RECAP *********************************************************************
192.168.1.1 : ok=3 changed=1 unreachable=0 failed=0
無事にdescriptionが設定されました。
interface GigabitEthernet1/0/1
description TESTTESTTEST
switchport access vlan 192
switchport mode access
end
Plyaybookの実行(2回目)
user@ubuntu-vm:/etc/ansible$ ansible-playbook cat_int.yml
PLAY [cisco] *******************************************************************
TASK [set description] *********************************************************
changed: [192.168.1.1]
TASK [DEBUG] *******************************************************************
ok: [192.168.1.1] => {
"result": {
"changed": true,
"responses": [
"",
""
],
"updates": [
"int gi1/0/1",
"description TESTTESTTEST"
]
}
}
RUNNING HANDLER [save config] **************************************************
ok: [192.168.1.1]
PLAY RECAP *********************************************************************
192.168.1.1 : ok=3 changed=1 unreachable=0 failed=0
おっと、変更ありとみなされ、descpriptionコマンドがまた実行されてしまいました。
これは、lines
に指定した「description TESTTESTTEST」を投入しようとして、
現状コンフィグの「description TESTTESTTEST」の親階層のコンフィグである
「interface GigabitEthernet1/0/1」がparents
に指定した「gi1/0/1」と
文字列的に一致しないため、「実行すべきコマンド」と判断され
configure terminal
int gi1/0/1
description TESTTESTTEST
が実行されたかたちとなります。冪等性がないといえます。
【パターン3】lines にフルスペル指定する
Playbookの内容
抜粋です。他はパターン1と同じです。
ios_config:
lines:
- interface GigabitEthernet1/0/1
- description TESTTESTTEST
Plyaybooの実行(1回目)
user@ubuntu-vm:/etc/ansible$ ansible-playbook cat_int.yml
PLAY [cisco] *******************************************************************
TASK [set description] *********************************************************
fatal: [192.168.1.1]: FAILED! => {"changed": false, "commands": ["configure terminal", "description TESTTESTTEST"], "failed": true, "msg": "matched error in response: description TESTTESTTEST\r\n ^\r\n% Invalid input detected at '^' marker.\r\n\r\nSW104(config)#"}
PLAY RECAP *********************************************************************
192.168.1.1 : ok=0 changed=0 unreachable=0 failed=1
おっと、エラーになってしまい、description コマンドが実行されませんでした。
このパターンでは「interface GigabitEthernet1/0/1」を lines
で指定しているため
現状コンフィグに「interface GigabitEthernet1/0/1」自身がある場合は省略されてしまいます。
その結果、debug結果にあるように、
configure terminal
description TESTTESTTEST
の2行のみを実行しようます。
グローバルコンフィグレーションモードに description コマンドはありませんので
エラーとなっています。
このパターンは使用できないことが分かりました。
【パターン4】lines に省略して指定する
Playbookの内容
抜粋です。他はパターン1と同じです。
ios_config:
lines:
- int gi1/0/1
- description TESTTESTTEST
Plyaybookの実行(1回目)
user@ubuntu-vm:/etc/ansible$ ansible-playbook cat_int.yml
PLAY [cisco] *******************************************************************
TASK [set description] *********************************************************
changed: [192.168.1.1]
TASK [DEBUG] *******************************************************************
ok: [192.168.1.1] => {
"result": {
"changed": true,
"responses": [
"",
""
],
"updates": [
"int gi1/0/1",
"description TESTTESTTEST"
]
}
}
RUNNING HANDLER [save config] **************************************************
ok: [192.168.1.1]
PLAY RECAP *********************************************************************
192.168.1.1 : ok=3 changed=1 unreachable=0 failed=0
無事にdescriptionが設定されました。
interface GigabitEthernet1/0/1
description TESTTESTTEST
switchport access vlan 192
switchport mode access
end
Plyaybookの実行(2回目)
user@ubuntu-vm:/etc/ansible$ ansible-playbook cat_int.yml
PLAY [cisco] *******************************************************************
TASK [set description] *********************************************************
changed: [192.168.1.1]
TASK [DEBUG] *******************************************************************
ok: [192.168.1.1] => {
"result": {
"changed": true,
"responses": [
"",
""
],
"updates": [
"int gi1/0/1",
"description TESTTESTTEST"
]
}
}
RUNNING HANDLER [save config] **************************************************
ok: [192.168.1.1]
PLAY RECAP *********************************************************************
192.168.1.1 : ok=3 changed=1 unreachable=0 failed=0
おっと、パターン2と同様に2回目も description コマンドが実行されてしまいました。
これは、lines
で指定した「int gi1/0/1」を投入しようとして、
現状コンフィグの「interface GigabitEthernet1/0/1」と一致しないため、「実行すべきコマンド」と判断され
configure terminal
int gi1/0/1
description TESTTESTTEST
が実行されたかたちとなります。冪等性がないといえます。
●まとめ
4パターンの検証結果から以下のことが分かりました。
パターンNo. | 階層コンフィグ指定場所 | コマンド | 正常実行 | 冪等性 |
---|---|---|---|---|
【パターン1】 | parents | フルスペル(interface) | ○ | ○ |
【パターン2】 | parents | 省略(int) | ○ | × |
【パターン3】 | lines | フルスペル(interface) | × | - |
【パターン4】 | lines | 省略(int) | ○ | × |
これらの結果から、interfaceのような階層指定のコンフィグは
parents
にフルスペルで指定するのが良い、という個人的なまとめとなりました。