てくなべ (tekunabe)

ansible / network / automation

[Ansible] netconf_get モジュールで Cisco IOS XE の情報を NETCONF で取得する

はじめに

以前、restconf_get モジュールで Cisco IOS XE のインターフェース情報を取得してみる という記事で、Ansible で RESTCONF 経由で情報取得する Playbook をご紹介しました。

この記事では RESTCONF ではく、netconf_get モジュールCisco IOS XE の情報を取得する Playbook をご紹介します。

サンプルは、 running-config、インターフェース状態、ルーティングテープルの取得です。

環境


■ 準備

Playook 実行に必要なファイルを作成しますす。

インベントリファイル

ホスト情報を示すインベントリファイルを作成します。

  • inventory.ini
[ios]
ios1 ansible_host=ios-xe-mgmt.cisco.com

変数定義ファイル

インベントリファイルで定義したグループ ios が利用する変数を定義するファイルを作成します。

  • group_vars/ios.yml
# ansible_network_os: ios  # 不要
ansible_connection: netconf
ansible_port: 10000
ansible_user: developer
ansible_password: dummy
変数名 説明
ansible_connection 一番のポイントです。netconf コネクションプラグインを利用するために netconf を指定します。
ansible_port NETCONF 接続に利用するポートです。netconf コネクションプラグインの場合のデフォルトは 830 です。ここでは環境の都合で 10000 を指定します。
ansible_user ユーザー名を指定します。
ansible_password ここではダミーの値を記載しています。必要に応じて ansible-vault で暗号化します。


■ Playbookサンプル1: running-config を取得

source オプションで running を指定すると、running-config を NETCONF / YANG 形式で取得できます。

Playbook

- hosts: ios
  gather_facts: no

  tasks:
    - name: get runnnig-config
      netconf_get:
        source: running
      register: result

    - name: debug result
      debug:
        msg: "{{ result.stdout }}"

実行結果

TASK [get runnnig-config] *******************************************************************************************************************************
unable to load netconf plugin for network_os ios, falling back to default plugin
ok: [ios1]

TASK [debug result] *************************************************************************************************************************************
ok: [ios1] => {
    "msg": "<data xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><native xmlns=\"http://cisco.com/ns/yang/Cisco-IOS-XE-native\"><version>16.11</version><boot-start-marker/><boot-end-marker/><banner><motd><banner>^C</banner></motd></banner><memory><free><low-watermark><processor>80557</processor></low-watermark></free></memory><call-home><contact-email-addr xmlns=\"http://cisco.com/ns/yang/Cisco-IOS-XE-call-home\">sch-smart-licensing@cisco.com</contact-email-addr><profile xmlns=\"http://cisco.com/ns/yang/Cisco-IOS-XE-call-home\"><profile-name>CiscoTAC-1</profile-name><active>true</active></profile></call-home><service><timestamps><debug><datetime><msec/></datetime></debug><log><datetime><msec/></datetime></log></timestamps><call-home/></service><platform><console xmlns=\"http://cisco.com/ns/yang/Cisco-IOS-XE-platform\"><output>virtual</output></console></platform><hostname>csr1000v-1</hostname><enable><secret><type>9</type><secret>$9$PvdeTeuxxh0ygk$PSg0GTG2I7bluI51e.IvfEu2uxy56e/9/PgqzFUklso</secret></secret></enable><username><name>cisco</name><privilege>15</privilege><secret><encryption>9</encryption><secret>$9$COf3Q4xfzT.JxE$L3hvSkDv874Qrh8Hzdv/rPQjLNOjreYG2ocffHG7rls</secret></secret></username><username><name>developer</name><privilege>15</privilege><secret><encryption>9</encryption><secret>$9$fhUXi6Xg438iAE$..VhXRCHiDQy3K2zmZUl9iZLbQJ9wpUtQZwQxSRESc2</secret></secret></username><username><name>root</name><privilege>15</privilege><secret><encryption>9</encryption><secret>$9$FfUDIPBFcs03AE$MyLIWEuiRle8p3yGflAGTcrJA6BUUh/oWtyyfoMQXSI</secret></secret></username><ip><domain><name>abc.inc</name></domain><forward-protocol><protocol>nd</protocol></forward-protocol><route><ip-route-interface-forwarding-list><prefix>0.0.0.0</prefix><mask>0.0.0.0</mask><fwd-list><fwd>GigabitEthernet1</fwd><interface-next-hop><ip-address>10.10.20.254</ip-address></interface-next-hop></fwd-list></ip-route-interface-forwarding-list></route><scp><server><enable/></server></scp><ssh><rsa><keypair-name>ssh-key</keypair-name></rsa><version>2</version></ssh><access-list><extended xmlns=\"http://cisco.com/ns/yang/Cisco-IOS-XE-acl\"><name>meraki-fqdn-dns</name></extended></access-list><http xmlns=\"http://cisco.com/ns/yang/Cisco-IOS-XE-http\"><authentication><local/></authentication><server>true</server><secure-server>true</secure-server></http></ip><interface><GigabitEthernet><name>1</name><description>MANAGEMENT INTERFACE - DON'T TOUCH ME</description><ip><address><primary><address>10.10.20.48</address><mask>255.255.255.0</mask></primary></address></ip><mop><enabled>false</enabled><sysid>false</sysid></mop><negotiation xmlns=\"http://cisco.com/ns/yang/Cisco-IOS-XE-ethernet\"><auto>true</auto></negotiation></GigabitEthernet><GigabitEthernet><name>2</name><description>Network Interface</description><shutdown/><mop><enabled>false</enabled><sysid>false</sysid></mop><negotiation xmlns=\"http://cisco.com/ns/yang/Cisco-IOS-XE-ethernet\"><auto>true</auto></negotiation></GigabitEthernet><GigabitEthernet><name>3</name><description>Network Interface</description><shutdown/><mop><enabled>false</enabled><sysid>false</sysid></mop><negotiation xmlns=\"http://cisco.com/ns/yang/Cisco-IOS-XE-ethernet\"><auto>true</auto></negotiation></GigabitEthernet></interface><control-plane/><login><on-success><log/></on-success></login><multilink><bundle-name xmlns=\"http://cisco.com/ns/yang/Cisco-IOS-XE-ppp\">authenticated</bundle-name></multilink><redundancy/><spanning-tree><extend xmlns=\"http://cisco.com/ns/yang/Cisco-IOS-XE-spanning-tree\"><system-id/></extend></spanning-tree><subscriber><templating/></subscriber><crypto><pki xmlns=\"http://cisco.com/ns/yang/Cisco-IOS-XE-crypto\"><certificate><chain><name>SLA-TrustPoint</name><certificate><serial>01</serial><certtype>ca</certtype></certificate></chain><chain><name>TP-self-signed-1059130051</name><certificate><serial>01</serial><certtype>self-signed</certtype></certificate></chain></certificate><trustpoint><id>SLA-TrustPoint</id><enrollment><pkcs12/></enrollment><revocation-check>crl</revocation-check></trustpoint><trustpoint><id>TP-self-signed-1059130051</id><enrollment><selfsigned/></enrollment><revocation-check>none</revocation-check><subject-name>cn=IOS-Self-Signed-Certificate-1059130051</subject-name></trustpoint></pki></crypto><license><udi><pid>CSR1000V</pid><sn>9MKH579CKHN</sn></udi><boot><level><ax/></level></boot></license><line><console><first>0</first><exec-timeout><minutes>0</minutes><seconds>0</seconds></exec-timeout><stopbits>1</stopbits></console><vty><first>0</first><last>4</last><login><local/></login><transport><input><input>ssh</input></input></transport></vty></line><diagnostic xmlns=\"http://cisco.com/ns/yang/Cisco-IOS-XE-diagnostics\"><bootup><level>minimal</level></bootup></diagnostic></native><licensing xmlns=\"http://cisco.com/ns/yang/cisco-smart-license\"><config><enable>false</enable><privacy><hostname>false</hostname><version>false</version></privacy><utility><utility-enable>false</utility-enable></utility></config></licensing><acl xmlns=\"http://openconfig.net/yang/acl\"><acl-sets><acl-set><name>meraki-fqdn-dns</name><type>ACL_IPV4</type><config><name>meraki-fqdn-dns</name><type>ACL_IPV4</type></config></acl-set></acl-sets></acl><interfaces xmlns=\"http://openconfig.net/yang/interfaces\"><interface><name>GigabitEthernet1</name><config><name>GigabitEthernet1</name><type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type><description>MANAGEMENT INTERFACE - DON'T TOUCH ME</description><enabled>true</enabled></config><subinterfaces><subinterface><index>0</index><config><index>0</index><description>MANAGEMENT INTERFACE - DON'T TOUCH ME</description><enabled>true</enabled></config><ipv4 xmlns=\"http://openconfig.net/yang/interfaces/ip\"><addresses><address><ip>10.10.20.48</ip><config><ip>10.10.20.48</ip><prefix-length>24</prefix-length></config></address></addresses></ipv4><ipv6 xmlns=\"http://openconfig.net/yang/interfaces/ip\"><config><enabled>false</enabled></config></ipv6></subinterface></subinterfaces><ethernet xmlns=\"http://openconfig.net/yang/interfaces/ethernet\"><config><mac-address>00:50:56:bb:e9:9c</mac-address><auto-negotiate>true</auto-negotiate></config></ethernet></interface><interface><name>GigabitEthernet2</name><config><name>GigabitEthernet2</name><type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type><description>Network Interface</description><enabled>false</enabled></config><subinterfaces><subinterface><index>0</index><config><index>0</index><description>Network Interface</description><enabled>false</enabled></config><ipv6 xmlns=\"http://openconfig.net/yang/interfaces/ip\"><config><enabled>false</enabled></config></ipv6></subinterface></subinterfaces><ethernet xmlns=\"http://openconfig.net/yang/interfaces/ethernet\"><config><mac-address>00:50:56:bb:77:1a</mac-address><auto-negotiate>true</auto-negotiate></config></ethernet></interface><interface><name>GigabitEthernet3</name><config><name>GigabitEthernet3</name><type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type><description>Network Interface</description><enabled>false</enabled></config><subinterfaces><subinterface><index>0</index><config><index>0</index><description>Network Interface</description><enabled>false</enabled></config><ipv6 xmlns=\"http://openconfig.net/yang/interfaces/ip\"><config><enabled>false</enabled></config></ipv6></subinterface></subinterfaces><ethernet xmlns=\"http://openconfig.net/yang/interfaces/ethernet\"><config><mac-address>00:50:56:bb:eb:1e</mac-address><auto-negotiate>true</auto-negotiate></config></ethernet></interface></interfaces><lldp xmlns=\"http://openconfig.net/yang/lldp\"><config><enabled>false</enabled></config><interfaces><interface><name>GigabitEthernet1</name><config><name>GigabitEthernet1</name><enabled>true</enabled></config></interface><interface><name>GigabitEthernet2</name><config><name>GigabitEthernet2</name><enabled>true</enabled></config></interface><interface><name>GigabitEthernet3</name><config><name>GigabitEthernet3</name><enabled>true</enabled></config></interface></interfaces></lldp><network-instances xmlns=\"http://openconfig.net/yang/network-instance\"><network-instance><name>default</name><config><name>default</name><type xmlns:oc-ni-types=\"http://openconfig.net/yang/network-instance-types\">oc-ni-types:DEFAULT_INSTANCE</type><description>default-vrf [read-only]</description></config><tables><table><protocol xmlns:oc-pol-types=\"http://openconfig.net/yang/policy-types\">oc-pol-types:DIRECTLY_CONNECTED</protocol><address-family xmlns:oc-types=\"http://openconfig.net/yang/openconfig-types\">oc-types:IPV4</address-family><config><protocol xmlns:oc-pol-types=\"http://openconfig.net/yang/policy-types\">oc-pol-types:DIRECTLY_CONNECTED</protocol><address-family xmlns:oc-types=\"http://openconfig.net/yang/openconfig-types\">oc-types:IPV4</address-family></config></table><table><protocol xmlns:oc-pol-types=\"http://openconfig.net/yang/policy-types\">oc-pol-types:DIRECTLY_CONNECTED</protocol><address-family xmlns:oc-types=\"http://openconfig.net/yang/openconfig-types\">oc-types:IPV6</address-family><config><protocol xmlns:oc-pol-types=\"http://openconfig.net/yang/policy-types\">oc-pol-types:DIRECTLY_CONNECTED</protocol><address-family xmlns:oc-types=\"http://openconfig.net/yang/openconfig-types\">oc-types:IPV6</address-family></config></table><table><protocol xmlns:oc-pol-types=\"http://openconfig.net/yang/policy-types\">oc-pol-types:STATIC</protocol><address-family xmlns:oc-types=\"http://openconfig.net/yang/openconfig-types\">oc-types:IPV4</address-family><config><protocol xmlns:oc-pol-types=\"http://openconfig.net/yang/policy-types\">oc-pol-types:STATIC</protocol><address-family xmlns:oc-types=\"http://openconfig.net/yang/openconfig-types\">oc-types:IPV4</address-family></config></table><table><protocol xmlns:oc-pol-types=\"http://openconfig.net/yang/policy-types\">oc-pol-types:STATIC</protocol><address-family xmlns:oc-types=\"http://openconfig.net/yang/openconfig-types\">oc-types:IPV6</address-family><config><protocol xmlns:oc-pol-types=\"http://openconfig.net/yang/policy-types\">oc-pol-types:STATIC</protocol><address-family xmlns:oc-types=\"http://openconfig.net/yang/openconfig-types\">oc-types:IPV6</address-family></config></table></tables><protocols><protocol><identifier xmlns:oc-pol-types=\"http://openconfig.net/yang/policy-types\">oc-pol-types:STATIC</identifier><name>DEFAULT</name><config><identifier xmlns:oc-pol-types=\"http://openconfig.net/yang/policy-types\">oc-pol-types:STATIC</identifier><name>DEFAULT</name></config><static-routes><static><prefix>0.0.0.0/0</prefix><config><prefix>0.0.0.0/0</prefix></config><next-hops><next-hop><index>GigabitEthernet1_10.10.20.254</index><config><index>GigabitEthernet1_10.10.20.254</index><next-hop>10.10.20.254</next-hop></config><interface-ref><config><interface>GigabitEthernet1</interface></config></interface-ref></next-hop></next-hops></static></static-routes></protocol><protocol><identifier xmlns:oc-pol-types=\"http://openconfig.net/yang/policy-types\">oc-pol-types:DIRECTLY_CONNECTED</identifier><name>DEFAULT</name><config><identifier xmlns:oc-pol-types=\"http://openconfig.net/yang/policy-types\">oc-pol-types:DIRECTLY_CONNECTED</identifier><name>DEFAULT</name></config></protocol></protocols></network-instance></network-instances><interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\"><interface><name>GigabitEthernet1</name><description>MANAGEMENT INTERFACE - DON'T TOUCH ME</description><type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type><enabled>true</enabled><ipv4 xmlns=\"urn:ietf:params:xml:ns:yang:ietf-ip\"><address><ip>10.10.20.48</ip><netmask>255.255.255.0</netmask></address></ipv4><ipv6 xmlns=\"urn:ietf:params:xml:ns:yang:ietf-ip\"/></interface><interface><name>GigabitEthernet2</name><description>Network Interface</description><type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type><enabled>false</enabled><ipv4 xmlns=\"urn:ietf:params:xml:ns:yang:ietf-ip\"/><ipv6 xmlns=\"urn:ietf:params:xml:ns:yang:ietf-ip\"/></interface><interface><name>GigabitEthernet3</name><description>Network Interface</description><type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type><enabled>false</enabled><ipv4 xmlns=\"urn:ietf:params:xml:ns:yang:ietf-ip\"/><ipv6 xmlns=\"urn:ietf:params:xml:ns:yang:ietf-ip\"/></interface></interfaces><nacm xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-acm\"><enable-nacm>true</enable-nacm><read-default>deny</read-default><write-default>deny</write-default><exec-default>deny</exec-default><enable-external-groups>true</enable-external-groups><rule-list><name>admin</name><group>PRIV15</group><rule><name>permit-all</name><module-name>*</module-name><access-operations>*</access-operations><action>permit</action></rule></rule-list></nacm><routing xmlns=\"urn:ietf:params:xml:ns:yang:ietf-routing\"><routing-instance><name>default</name><description>default-vrf [read-only]</description><routing-protocols><routing-protocol><type>static</type><name>1</name><static-routes><ipv4 xmlns=\"urn:ietf:params:xml:ns:yang:ietf-ipv4-unicast-routing\"><route><destination-prefix>0.0.0.0/0</destination-prefix><next-hop><outgoing-interface>GigabitEthernet1</outgoing-interface></next-hop></route></ipv4></static-routes></routing-protocol></routing-protocols></routing-instance></routing></data>"
}


■ Playbookサンプル2: インターフェースの状態を取得

filter オプションで、XMLで階層を指定すると取得する情報を絞れます。

インターフェースの情報は以下のようなフィルターをかけます。(参考: ietf-interfaces.yang

          <interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
          </interfaces-state>

コマンドでいうと、show interfaces あたりでしょうか。

Playbook

- hosts: ios
  gather_facts: no

  tasks:
    - name: get interfaces state
      netconf_get:
        filter: |-
          <interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
          </interfaces-state>
      register: result

    - name: debug result
      debug:
        msg: "{{ result.stdout }}"

実行結果

TASK [get interfaces state] *****************************************************************************************************************************
unable to load netconf plugin for network_os ios, falling back to default plugin
ok: [ios1]

TASK [debug result] *************************************************************************************************************************************
ok: [ios1] => {
    "msg": "<data xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><interfaces-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\"><interface><name>GigabitEthernet1</name><type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type><admin-status>up</admin-status><oper-status>up</oper-status><last-change>2020-06-12T23:57:31.000876+00:00</last-change><if-index>1</if-index><phys-address>00:50:56:bb:e9:9c</phys-address><speed>1024000000</speed><statistics><discontinuity-time>2020-06-12T23:56:13.00004+00:00</discontinuity-time><in-octets>5425046053</in-octets><in-unicast-pkts>9040594</in-unicast-pkts><in-broadcast-pkts>0</in-broadcast-pkts><in-multicast-pkts>0</in-multicast-pkts><in-discards>0</in-discards><in-errors>0</in-errors><in-unknown-protos>0</in-unknown-protos><out-octets>36343921</out-octets><out-unicast-pkts>118825</out-unicast-pkts><out-broadcast-pkts>0</out-broadcast-pkts><out-multicast-pkts>0</out-multicast-pkts><out-discards>0</out-discards><out-errors>0</out-errors></statistics></interface><interface><name>GigabitEthernet2</name><type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type><admin-status>down</admin-status><oper-status>down</oper-status><last-change>2020-06-12T23:57:23.000416+00:00</last-change><if-index>2</if-index><phys-address>00:50:56:bb:77:1a</phys-address><speed>1024000000</speed><statistics><discontinuity-time>2020-06-12T23:56:13.00004+00:00</discontinuity-time><in-octets>300</in-octets><in-unicast-pkts>5</in-unicast-pkts><in-broadcast-pkts>0</in-broadcast-pkts><in-multicast-pkts>0</in-multicast-pkts><in-discards>0</in-discards><in-errors>0</in-errors><in-unknown-protos>0</in-unknown-protos><out-octets>0</out-octets><out-unicast-pkts>0</out-unicast-pkts><out-broadcast-pkts>0</out-broadcast-pkts><out-multicast-pkts>0</out-multicast-pkts><out-discards>0</out-discards><out-errors>0</out-errors></statistics></interface><interface><name>GigabitEthernet3</name><type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type><admin-status>down</admin-status><oper-status>down</oper-status><last-change>2020-06-12T23:57:23.00042+00:00</last-change><if-index>3</if-index><phys-address>00:50:56:bb:eb:1e</phys-address><speed>1024000000</speed><statistics><discontinuity-time>2020-06-12T23:56:13.00004+00:00</discontinuity-time><in-octets>120</in-octets><in-unicast-pkts>2</in-unicast-pkts><in-broadcast-pkts>0</in-broadcast-pkts><in-multicast-pkts>0</in-multicast-pkts><in-discards>0</in-discards><in-errors>0</in-errors><in-unknown-protos>0</in-unknown-protos><out-octets>0</out-octets><out-unicast-pkts>0</out-unicast-pkts><out-broadcast-pkts>0</out-broadcast-pkts><out-multicast-pkts>0</out-multicast-pkts><out-discards>0</out-discards><out-errors>0</out-errors></statistics></interface><interface><name>Control Plane</name><type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:other</type><admin-status>up</admin-status><oper-status>up</oper-status><last-change>2020-06-12T23:57:20.000993+00:00</last-change><if-index>0</if-index><phys-address>00:00:00:00:00:00</phys-address><speed>10240000000</speed><statistics><discontinuity-time>2020-06-12T23:56:13.00004+00:00</discontinuity-time><in-octets>0</in-octets><in-unicast-pkts>0</in-unicast-pkts><in-broadcast-pkts>0</in-broadcast-pkts><in-multicast-pkts>0</in-multicast-pkts><in-discards>0</in-discards><in-errors>0</in-errors><in-unknown-protos>0</in-unknown-protos><out-octets>0</out-octets><out-unicast-pkts>0</out-unicast-pkts><out-broadcast-pkts>0</out-broadcast-pkts><out-multicast-pkts>0</out-multicast-pkts><out-discards>0</out-discards><out-errors>0</out-errors></statistics></interface></interfaces-state></data>"
}

netconf_get モジュールでは、display オプションで json を指定することで、表示を JSON にすることができます。前に pip install jxmlease しておく必要があります。

Playbook (JSON版)

- hosts: ios
  gather_facts: no

  tasks:
    - name: get interfaces state
      netconf_get:
        filter: |-
          <interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
          </interfaces-state>
        display: json
      register: result

    - name: debug result
      debug:
        msg: "{{ result.output }}"  # .stdout ではなく .output

実行結果 (JSON版)

TASK [debug result] *************************************************************************************************************************************
ok: [ios1] => {
    "msg": {
        "data": {
            "interfaces-state": {
                "interface": [
                    {
                        "admin-status": "up",
                        "if-index": "1",
                        "last-change": "2020-06-12T23:57:31.000864+00:00",
                        "name": "GigabitEthernet1",
                        "oper-status": "up",
...(略)...


■ サンプル3: ルーティングテーブルの取得

ルーティングテーブルを取得したい場合は、以下のようなフィルターをかけます、(参考: ietf-routing.yang

          <routing-state xmlns="urn:ietf:params:xml:ns:yang:ietf-routing">
          </routing-state>

先程指定した display: json をここでも指定します。

Playbook

- hosts: ios
  gather_facts: no

  tasks:
    - name: get routing table
      netconf_get:
        filter: |-
          <routing-state xmlns="urn:ietf:params:xml:ns:yang:ietf-routing">
          </routing-state>
        display: json
      register: result

    - name: debug result
      debug:
        msg: "{{ result.output }}"  # .stdout ではなく .output

実行結果

TASK [get routing table] ********************************************************************************************************************************
unable to load netconf plugin for network_os ios, falling back to default plugin
ok: [ios1]

TASK [debug result] *************************************************************************************************************************************
ok: [ios1] => {
    "msg": {
        "data": {
            "routing-state": {
                "routing-instance": [
                    {
                        "name": "default",
                        "ribs": {
                            "rib": [
                                {
                                    "address-family": "ipv4",
                                    "default-rib": "false",
                                    "name": "ipv4-default",
                                    "routes": {
                                        "route": [
                                            {
                                                "active": "",
                                                "destination-prefix": "0.0.0.0/0",
                                                "metric": "1",
                                                "next-hop": {
                                                    "next-hop-address": "10.10.20.254",
                                                    "outgoing-interface": "GigabitEthernet1"
                                                },
                                                "route-preference": "1",
                                                "source-protocol": "static"
                                            },
                                            {
                                                "active": "",
                                                "destination-prefix": "10.10.20.0/24",
                                                "metric": "0",
                                                "next-hop": {
                                                    "next-hop-address": "0.0.0.0",
                                                    "outgoing-interface": "GigabitEthernet1"
                                                },
                                                "route-preference": "0",
                                                "source-protocol": "direct"
                                            },
                                            {
                                                "active": "",
                                                "destination-prefix": "10.10.20.48/32",
                                                "metric": "0",
                                                "next-hop": {
                                                    "next-hop-address": "0.0.0.0",
                                                    "outgoing-interface": "GigabitEthernet1"
                                                },
                                                "route-preference": "0",
                                                "source-protocol": "direct"
                                            }
                                        ]
                                    }
                                },
                                {
                                    "address-family": "ipv6",
                                    "default-rib": "false",
                                    "name": "ipv6-default"
                                }
                            ]
                        },
                // ...(略)...
                ]
            }
        }
    }
}


■ おわりに

RESTCONF 同様、NETCONF は 構造化データを扱えるため、assert モジュールによる状態確認や、レポートに応用しやすいと思いました。