Ansible×NetconfでIOSXRに設定してみる

# Ansible×Netconfの可能性
先日書いた[AnsibleでNW機器の情報取得してみた(IOSXR)](https://qiita.com/snamon/items/7756687e108964fb58a1)の中で【netconfで設定を取ってみる】というものを実施しましたが、今回はNetconfで設定変更をしてみた。という記事なります。

Netconfについての細かい説明は[知ったかぶりしないNetconf](https://codeout.hatenablog.com/entry/2014/10/24/230013)などを参考ください。


ネットワークの課題の一つに、マルチベンダによる設定方法の違いがあります。
現場内でも、マルチに手順書が作れる人がいれば、この機器担当の人などがいることがしばしばあります。同じベンダの機器でも機種によっては設定方法が異なっていたり、手順が多少違うこともあり、専門の知識が必要になります。

さらに、ネットワーク機器の設定方法のほとんどは手続き型とよばれる、目的の状態にするまで手続きをしていくものが多く存在しています。
(CiscoIOSやNXOS,ASA)
１つの設定単位は複雑ではありませんが、手続きを正確に行わないと目的の状態にすることができません。

ネットワークをマネジメントするプロトコルとして設定変更に弱いSNMP(UDPで通信)ではなく、新しいNetconfというものを考えました！
そこでYANGというデータの定義のルールでやります！
というところまで理解しました。

これによりマルチベンダでも同じYANGで定義されたデータ7をNetconfで設定変更することが可能になります。
さらに従来の手続き型ではなく、宣言型での設定が可能になります。

# Ansible モジュール
IOSXR専用の公式ページがあり、そこでNetconfについても紹介されています
詳細については[こちら](https://docs.ansible.com/ansible/latest/network/user_guide/platform_iosxr.html)を参考ください

読み進めていくとNetconfに対応しているモジュールが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246478/9a85da83-a4a6-d239-8ae2-82ab2a8e80bd.png)

バナーだったり、インターフェイスだったりロギングの設定だったり、ユーザだったり、システム周りの設定がNetconfで可能なようです。

が、
### **netconfでルーティングの設定がしたい～～～～～～**
ということで
[netconf_configというモジュール](https://docs.ansible.com/ansible/latest/modules/netconf_config_module.html?highlight=netconf#requirements)で実装してみました。

重要そうなパラメータを抜粋してみました。

|パラメータ|設定値|説明|
|:--|:--|:--|
|backup|boolen(True or False)|バックアップを取得するか？|
|backup_options|dir_path: ,filename:|どこのパスに、何て名前でバックアップファイルを保存するか
|commit|boolen(True or False)|コミットするか？
|content|-|どんなコンテンツを送るか(どんなConfigを送るか)
|default_operation|[merge] or [replace] or [none]|マージ(追加)するかリプレイス(置き換え)するか
|error_option|[stop-on-error] or [continue-on-error] or [rollback-on-error]|エラー時の挙動
|lock|[never] or [always] or [if-supported]|作業中のConfigLock
|validate|boolen(True or False)|コンフィグの検証をしてくれる(接続機器側に検証機能があれば)|

# 実装編

それではさっそくPlaybookを実装しましょう。

[作業の手順]
　　1.事前Config取得
　　2.設定変更
　　3.事後Config取得

```inventory.ini
[iosxr]
sbx-iosxr-mgmt.cisco.com

[iosxr:vars]
ansible_network_os=iosxr
ansible_user=admin
ansible_password=C1sco12345
ansible_port=10000
ansible_connection=netconf
```

検証をしながらだったので、変数をいろんなところで定義しちゃってます。。(反省)
そしてあまり必要もないのにrole化しています。

```editConfig.yml
---
- hosts: all
  gather_facts: no

  roles:
    - edit_config
```

`roles/edit_config/tasks/main.yml` は以下の通りです。
今回はCommitはせずに、CandidateConfigの差分を確認するまでにとどめています。
投入するConfigは include_vars: "{{ inventory_hostname }}_config.yml"で読み込み
その中にあるipv4Routeで定義しています。

```roles/edit_config/tasks/main.yml
---
- name: 対象のConfigをインポート
  include_vars: "{{ inventory_hostname }}_config.yml"

- name: 事前Routing(ipv4)を取得
  netconf_get:
    source: candidate
    filter: |
      <router-static xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-ip-static-cfg">
      </router-static>
    display: pretty
  register: netconf_result

- name: 事前Config表示
  debug:
    msg: "{{ netconf_result.stdout }}"

- name: NetconfでConfig設定
  netconf_config:
    backup: True
    content: "{{ ipv4Route }}"
    commit: no
    default_operation: replace
    backup_options:
      filename: "{{ inventory_hostname }}.xml"
  register: netconf_result
  when: ansible_connection == "netconf"

- name: 事後Routing(ipv4)を取得
  netconf_get:
    source: candidate
    filter: |
      <router-static xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-ip-static-cfg">
      </router-static>
    display: pretty
  register: netconf_result

- name: 事前Config表示
  debug:
    msg: "{{ netconf_result.stdout }}"
```

変数ファイル

```roles/edit_config/vars/sbx-iosxr-mgmt.cisco.com._config.yml
---
ipv4Route: |
  <config>
    <router-static xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-ip-static-cfg">
      <default-vrf>
        <address-family>
          <vrfipv4>
            <vrf-unicast>
              <vrf-prefixes>
                <vrf-prefix>
                  <prefix>0.0.0.0</prefix>
                  <prefix-length>0</prefix-length>
                  <vrf-route>
                    <vrf-next-hop-table>
                      <vrf-next-hop-next-hop-address>
                        <next-hop-address>10.10.20.254</next-hop-address>
                      </vrf-next-hop-next-hop-address>
                    </vrf-next-hop-table>
                  </vrf-route>
                </vrf-prefix>
                <vrf-prefix>
                  <prefix>8.8.8.8</prefix>
                  <prefix-length>32</prefix-length>
                  <vrf-route>
                    <vrf-next-hop-table>
                      <vrf-next-hop-next-hop-address>
                        <next-hop-address>10.10.20.254</next-hop-address>
                      </vrf-next-hop-next-hop-address>
                    </vrf-next-hop-table>
                  </vrf-route>
                </vrf-prefix>
              </vrf-prefixes>
            </vrf-unicast>
          </vrfipv4>
        </address-family>
      </default-vrf>
    </router-static>
  </config>

```


# 動作確認
それではansible-playbookコマンドで実施します。

```
PLAY [all] *************************************************************************************************************************************************************************************************

TASK [edit_config : 対象のConfigをインポート] ***********************************************************************************************************************************************************************
ok: [sbx-iosxr-mgmt.cisco.com]

TASK [edit_config : 事前Routing(ipv4)を取得] ********************************************************************************************************************************************************************
ok: [sbx-iosxr-mgmt.cisco.com]

TASK [edit_config : 事前Config表示] ****************************************************************************************************************************************************************************
ok: [sbx-iosxr-mgmt.cisco.com] => 
  msg: |-
    <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
      <router-static xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-ip-static-cfg">
       <default-vrf>
        <address-family>
         <vrfipv4>
          <vrf-unicast>
           <vrf-prefixes>
            <vrf-prefix>
             <prefix>0.0.0.0</prefix>
             <prefix-length>0</prefix-length>
             <vrf-route>
              <vrf-next-hop-table>
               <vrf-next-hop-next-hop-address>
                <next-hop-address>10.10.20.254</next-hop-address>
               </vrf-next-hop-next-hop-address>
              </vrf-next-hop-table>
             </vrf-route>
            </vrf-prefix>
           </vrf-prefixes>
          </vrf-unicast>
         </vrfipv4>
        </address-family>
       </default-vrf>
      </router-static>
     </data>

TASK [edit_config : NetconfでConfig設定] **********************************************************************************************************************************************************************
ok: [sbx-iosxr-mgmt.cisco.com]

TASK [edit_config : 事後Routing(ipv4)を取得] ********************************************************************************************************************************************************************
ok: [sbx-iosxr-mgmt.cisco.com]

TASK [edit_config : 事前Config表示] ****************************************************************************************************************************************************************************
ok: [sbx-iosxr-mgmt.cisco.com] => 
  msg: |-
    <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
      <router-static xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-ip-static-cfg">
       <default-vrf>
        <address-family>
         <vrfipv4>
          <vrf-unicast>
           <vrf-prefixes>
            <vrf-prefix>
             <prefix>0.0.0.0</prefix>
             <prefix-length>0</prefix-length>
             <vrf-route>
              <vrf-next-hop-table>
               <vrf-next-hop-next-hop-address>
                <next-hop-address>10.10.20.254</next-hop-address>
               </vrf-next-hop-next-hop-address>
              </vrf-next-hop-table>
             </vrf-route>
            </vrf-prefix>
            <vrf-prefix>
             <prefix>8.8.8.8</prefix>
             <prefix-length>32</prefix-length>
             <vrf-route>
              <vrf-next-hop-table>
               <vrf-next-hop-next-hop-address>
                <next-hop-address>10.10.20.254</next-hop-address>
               </vrf-next-hop-next-hop-address>
              </vrf-next-hop-table>
             </vrf-route>
            </vrf-prefix>
           </vrf-prefixes>
          </vrf-unicast>
         </vrfipv4>
        </address-family>
       </default-vrf>
      </router-static>
     </data>

PLAY RECAP *************************************************************************************************************************************************************************************************
sbx-iosxr-mgmt.cisco.com   : ok=6    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

```

実はこれ、同じ処理をかけた2回目のLogなんですが、実行結果がOKになってしまう。(冪等性があるという状態)事前と事後では想定通りにルートが追加されている。

何故？？

# まとめ
初めてNetconfで設定変更をしてみました。
Ansibleを使うことで簡単に実施できますね！という感じではなかったです。
というのもNetconfについても私が知らなすぎる、、、

マルチベンダで利用しやすいのかな？とおもったんですが、
設定投入時に`xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-ip-static-cfg"`とベンダ指定をしているのが気になりました、、ここをベンダごとに変えれば同じ構造でつかえるのかなぁ、
検証もしたいですが、マルチベンダで試せる環境ってなかなかないですねよね。


とまぁここらへんで失礼します。