Ansibleのios_configモジュールでinterfaceコマンドはparentsに指定するのが良さそう(検証付き)

  • 3
    いいね
  • 1
    コメント

●はじめに

Ansibleの Cisco IOS の設定変更に対応するモジュール「ios_config」にはコンフィグを指定するオプションが複数あります。
linesはメイン処理、parentsは「interface Gi1/0/1」などの階層指定、beforeは事前処理、afterは事後処理といった具合です。

このうち、linesparentsについて
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の内容

pattern01.yml
---
- 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と同じです。

pattern02.yml
      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と同じです。

pattern03.yml
      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と同じです。

pattern04.yml
      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にフルスペルで指定するのが良い、という個人的なまとめとなりました。