てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] Ansible 2.9 からデフォルトでネットワークの fact も収集される

■ はじめに

fact といえば、サーバー系モジュールの場合は、gather_facts: yes(デフォルト)で収集されましたが、ネットワークモジュールの場合は事情が異なりました

具体的には、gather_facts: yes では、Ansible コントロールノード自身の fact が収集されていました。ネットワーク機器側の fact を収集するには ios_facts モジュールや、junos_facts モジュールなど、プラットフォーム個別の *_facts モジュールを使う必要がありました。

Ansible 2.9 では、gather_facts: yes(デフォルト)でネットワーク機器側の fact が収集されるようになりました。逆にAnsible コントロールノード自身の fact は収集されなくなりました。

この記事では、IOS を対象にして、簡単な例をもとに説明します。

※ ログのみやすさのため、CALLBACK PLUGIN を YAML に変更しています。

  • 環境
    • Ansible 2.9.0


■ デフォルトではコンフィグも収集される

デフォルトで、gather_facts: yes なので、そのまま試します。debug モジュールで、fact の名前空間である、ansible_facts をまるごと出力します。

  • Playbook
- hosts: ios

  tasks:
    - name: debug facts
      debug:
        var: ansible_facts
  • 実行

この場合、ios_facts モジュールでいうと gather_subset: all で fact を収集します。 つまり、下記のように コンフィグも収集 されます。

$ ansible-playbook -i ../inventory.ini fact_test.yml 

PLAY [ios] ******************************************************************************

TASK [Gathering Facts] ******************************************************************
[WARNING]: Ignoring timeout(10) for ios_facts

ok: [ios1]

TASK [debug facts] **********************************************************************
ok: [ios1] => 
  ansible_facts:
    _facts_gathered: true
    discovered_interpreter_python: /usr/bin/python
    net_all_ipv4_addresses:
    - 172.16.100.1
    - 10.10.20.48
    net_all_ipv6_addresses: []
    net_api: cliconf
    net_config: |-
      !
      ! Last configuration change at 12:35:22 UTC Sun Nov 24 2019 by developer
      !
      version 16.11
      service timestamps debug datetime msec
      service timestamps log datetime msec
      service call-home
      platform qfp utilization monitor load 80
      no platform punt-keepalive disable-kernel-core

      ...(略)...

      end
    net_filesystems:
    - 'bootflash:'
    net_filesystems_info:
      'bootflash:':
        spacefree_kb: 5793276.0
        spacetotal_kb: 7712692.0
    net_gather_network_resources: []
    net_gather_subset:
    - hardware
    - default
    - interfaces
    - config
    net_hostname: csr1000v-1
    net_image: bootflash:packages.conf
    net_interfaces:
      GigabitEthernet1:
        bandwidth: 1000000
        description: MANAGEMENT INTERFACE - DON'T TOUCH ME
        duplex: Full
        ipv4:
        - address: 10.10.20.48
          subnet: '24'
        lineprotocol: up
        macaddress: 0050.56bb.e99c
        mediatype: Virtual
        mtu: 1500
        operstatus: up
        type: CSR vNIC

      ...(略)...

    net_iostype: IOS-XE
    net_memfree_mb: 2074004.25
    net_memtotal_mb: 2378439.3125
    net_model: CSR1000V
    net_neighbors: {}
    net_python_version: 2.7.10
    net_serialnum: XXXXXXXXXXX
    net_system: ios
    net_version: 16.11.01a
    network_resources: {}

PLAY RECAP ******************************************************************************
ios1    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


gather_facts: yes のまま収集対象を絞るには

先ほどの例は gather_subset: all 相当だったので、不要な情報もあったかもしれません。そもそも fact 収集が不要であれば gather_facts: no にしますが、gather_facts: yes のまま収集対象を制限したいケースもあるかと思います。

module_defaultsを利用して、ios_facts モジュールの gather_subset オプションを指定することで必要な情報に制限できます。

・・・と思って試したのですが、うまく制限できませんでした。

公式ブログにも掲載されている方法ですが、微妙に試し方が誤っているのかもしれません。

うまく制限できなかったものの、ひとまずログとして残しておきます。

  • Playbook
- hosts: ios
  module_defaults:   # 暗黙的に実行される ios_facts のオプションを指定しておく
    ios_facts:
      gather_subset: "!config"   # コンフィグを ! で除外
 
  tasks:
    - name: debug facts
      debug:
        var: ansible_facts
  • 実行
$ ansible-playbook -i ../inventory.ini fact_test.yml 

PLAY [ios] ***********************************************************************

TASK [Gathering Facts] *******************************************************************
[WARNING]: Ignoring timeout(10) for ios_facts

ok: [ios1]

TASK [debug facts] **********************************************************************
ok: [ios1] => 
  ansible_facts:
    _facts_gathered: true
    discovered_interpreter_python: /usr/bin/python
    net_all_ipv4_addresses:
    - 172.16.100.1
    - 10.10.20.48
    net_all_ipv6_addresses: []
    net_api: cliconf
    net_config: |-
      !
      ! Last configuration change at 13:11:27 UTC Sun Nov 24 2019 by developer
      !
      version 16.11
      service timestamps debug datetime msec
      service timestamps log datetime msec
      service call-home
      platform qfp utilization monitor load 80
      no platform punt-keepalive disable-kernel-core

      ...(略)...

      end
    net_filesystems:
    - 'bootflash:'
    net_filesystems_info:
      'bootflash:':
        spacefree_kb: 5793252.0
        spacetotal_kb: 7712692.0
    net_gather_network_resources: []
    net_gather_subset:
    - hardware
    - default
    - interfaces
    - config
    net_hostname: csr1000v-1
    net_image: bootflash:packages.conf
    net_interfaces:
      GigabitEthernet1:
        bandwidth: 1000000
        description: MANAGEMENT INTERFACE - DON'T TOUCH ME
        duplex: Full
        ipv4:
        - address: 10.10.20.48
          subnet: '24'
        lineprotocol: up
        macaddress: 0050.56bb.e99c
        mediatype: Virtual
        mtu: 1500
        operstatus: up
        type: CSR vNIC

        ...(略)...

    net_iostype: IOS-XE
    net_memfree_mb: 2074004.25
    net_memtotal_mb: 2378439.3125
    net_model: CSR1000V
    net_neighbors: {}
    net_python_version: 2.7.10
    net_serialnum: XXXXXXXXXXX
    net_system: ios
    net_version: 16.11.01a
    network_resources: {}

PLAY RECAP ******************************************************************************
ios1       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

ということで、意図せずコンフィグも収集されてしまいました。module_defaults で指定した内容が反映されていないように見えます。なにか分かったら更新します。

[2019/11/24追記] ansible.cfgDEFAULT_GATHER_SUBSETに設定したら効きましが、影響範囲が広すぎますね。。


■ まとめ

  • Ansible 2.8 までは ios_facts モジュールなど、プラットフォーム個別の fact 収集モジュールで fact を収集していた
  • Ansible 2.9 でネットワークモジュールも gather_facts: yes (デフォルト) で fact が収集されるようになった
  • *_facts モジュールでいう、gather_subset: all 相当なので、コンフィグも収集される
  • 対象を制限るには module_defaults を利用すれば、よい・・はず・・・だが、今回の試し方ではうまくいかなかった

参考