AnsibleでCisco IOSの情報収集 - ios_facts

#背景
AnsibleでCiscoというと、Nexus(NXOS)のイメージが強いが、IOSモジュールもサポートが増えている（Catalystや小さいルータでも使える？）。試しやすいのはもちろん、情報取得と保存、加工など、普通のLAN/WANでも使えるかもしれない。そこで、[Ansible Docs](http://docs.ansible.com/ansible/list_of_network_modules.html)にあるIOSモジュールをいくつか確認してみた。この記録は、[ios_facts](http://docs.ansible.com/ansible/ios_facts_module.html)の場合。

※ansible.cfgやinventoryの設定は省略。

#環境
ローカルはCentOS。リモートデバイスはCSR1000vですが、IOSだと何でも良さそう。

```bash:version
[vagrant@localhost ansible]$ cat /etc/redhat-release 
CentOS Linux release 7.2.1511 (Core) 
[vagrant@localhost ansible]$ 
[vagrant@localhost ansible]$ ansible --version | grep 2.2
ansible 2.2.1.0
```

#Playbookサンプル - ios_facts

Ansible version 2.2でサポートされたネットワークモジュール [ios_facts](http://docs.ansible.com/ansible/ios_facts_module.html) を使って情報収集しファイルに保存するPlaybookサンプル。

- gather_facts: no のサンプルが多いが、yesにするとシステム変数（ansible_date_timeなど）が使える。この例ではファイル名に利用。
- gather_subset: はとりあえず all。
- ios_factsモジュールが返す変数のうち、ansible_net_hostnameはファイル名に利用。

```yaml:ios_facts.yml
---
- hosts: ios
  gather_facts: yes
  connection: local

  tasks:
    - ios_facts:
        gather_subset: all
        provider: "{{ cli }}"
      register: result

    #- name: For Debug
      #debug: var=result
      #debug: var=ansible_net_config
      #debug:
      #  msg: "{{ result }}"

    - copy:
        content: "{{ result }}"
        dest: "file/{{ ansible_date_time.year }}{{ ansible_date_time.month }}{{ ansible_date_time.day }}{{ ansible_date_time.hour }}{{ ansible_date_time.minute }}{{ ansible_date_time.second }}_{{ ansible_net_hostname }}_iosfacts.txt"

  vars:
    cli:
      host: "{{ inventory_hostname }}"
      authorize: yes
      username: "{{ ansible_ssh_user }}"
      password: "{{ ansible_ssh_pass }}"
      auth_pass: "{{ enable_pass }}"
```




#実行例

ios_factsの全内容（gather_subset: all）をファイル保存。ファイル名は、日付＋ホスト名＋テキストで重複しないように。見ながら実行するときはVerboseモード（-vvvvとか）にすると細かく確認できる。

```bash:ios_facts.yml
[vagrant@localhost ansible]$ ls ./file/
[vagrant@localhost ansible]$ 
[vagrant@localhost ansible]$ ansible-playbook ios_facts.yml

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

TASK [setup] *******************************************************************
ok: [10.71.130.58]

TASK [ios_facts] ***************************************************************
ok: [10.71.130.58]

TASK [copy] ********************************************************************
changed: [10.71.130.58]

PLAY RECAP *********************************************************************
10.71.130.58               : ok=3    changed=1    unreachable=0    failed=0   

[vagrant@localhost ansible]$ 
[vagrant@localhost ansible]$ ls ./file/
20170323060644_CSR-2_iosfacts.txt
[vagrant@localhost ansible]$ 
```

#ファイル確認

ファイルの中身はJSONなので、参照や加工など再利用が楽に行えるのが便利。また、ios_factsでは、あらかじめ定義された[Return Value](http://docs.ansible.com/ansible/ios_facts_module.html#return-values)がキーとして使えるところが特徴。（以下のログはjqで整形）

```json:20170323060644_CSR-2_iosfacts.txt
[vagrant@localhost ansible]$ cat file/20170323060644_CSR-2_iosfacts.txt | jq .
{
  "failed_commands": [],
  "ansible_facts": {
    "ansible_net_config": "Building configuration...\n\nCurrent configuration : 5284 bytes\n!\n! Last configuration change at 23:49:11 UTC Wed Mar 22 2017 by ********\n!\nversion 16.4\nservice timestamps debug datetime msec\nservice timestamps log datetime msec\nno platform punt-keepalive disable-kernel-core\nplatform console auto\n!\nhostname CSR-2\n!\nboot-start-marker\nboot-end-marker\n!\n!\nenable secret 5 $1$gi3J$VCM0Q9b3ZbHjDmBPhHG8i1\n!\n!\ntransport-map type persistent webui https-webui\n secure-server\n!\naaa new-model\n!\n!\naaa authorization exec default local \n!\n!\n!\n!\n!\naaa session-id common\n!\n!\n!\n!\n!\n!\n!\n!\n!\n\n\n\nno ip domain lookup\nip domain name solse.local\n!\n!\n!\n!\n!\n!\n!\n!\n!\n!\nsubscriber templating\n!\n!\n!\n!\nflow exporter test\n!\nmultilink bundle-name authenticated\n!\n!\n!\n!\n!\ncrypto pki trustpoint TP-self-signed-4057790232\n enrollment selfsigned\n subject-name cn=IOS-Self-Signed-Certificate-4057790232\n revocation-check none\n rsakeypair TP-self-signed-4057790232\n!\n!\ncrypto pki certificate chain TP-self-signed-4057790232\n certificate self-signed 01\n  30820330 30820218 A0030201 02020101 300D0609 2A864886 F70D0101 05050030 \n  31312F30 2D060355 04031326 494F532D 53656C66 2D536967 6E65642D 43657274 \n  69666963 6174652D 34303537 37393032 3332301E 170D3137 30323037 31333331 \n  30375A17 0D323030 31303130 30303030 305A3031 312F302D 06035504 03132649 \n  4F532D53 656C662D 5369676E 65642D43 65727469 66696361 74652D34 30353737 \n  39303233 32308201 22300D06 092A8648 86F70D01 01010500 0382010F 00308201 \n  0A028201 0100C7AE F7897749 1EF91458 582D1CF9 FF2BBD3A 84DFBB20 1C5733B2 \n  F105F042 CCC7E7B1 9FD64D11 FEAB00D8 C1E131A7 00049E1A DF2808FF B1FC0268 \n  B8DE8979 6C8C46CE 845B3A61 74347679 F18F9493 F56D8CAB F1F4FB33 C2873754 \n  E5C66038 AA335209 1D5798E2 2C0A2E11 FDC46B8C 0E1C3F04 F99F5723 EF5A07BD \n  5974A25D 0607738A 4BD70F8C E0CAB1C9 B69E49B4 4A2B01AB 735BE93F 29F7201B \n  FCE6F06A 023170BC 5FD2CADB EE1D2534 490FE743 B1335330 C765E34A F5776E8D \n  ED50A725 485B808B 03EB1E75 543EEC8B 659EED68 3B3F96A2 BD8C042F F368DE6F \n  1CB6E1E6 55077E45 119BC2D1 BD5DC3C6 15C3E877 BF13762C 78362E02 E0AE8F86 \n  18924D6D 354B0203 010001A3 53305130 0F060355 1D130101 FF040530 030101FF \n  301F0603 551D2304 18301680 14DACFB7 B6CEB10E B561279E 7E3143F0 3E0A8484 \n  74301D06 03551D0E 04160414 DACFB7B6 CEB10EB5 61279E7E 3143F03E 0A848474 \n  300D0609 2A864886 F70D0101 05050003 82010100 32226C2A E6AB6D46 1F3A6077 \n  B95BDE7C 1F8CCF6B E2AA5FC6 6481D835 0696DC0D 32CB60DB FB2833AF E2D302D9 \n  DFA0B764 E6DDA037 EF84FC50 BCBB2A95 EDBFBD0E 9D49AAAA 56D94B9F 0D20BA85 \n  8F9BE5AB 3888DC7D 6F4DE91A 15EEFCC7 2DA500C3 9AF1BBD4 DCB994E8 A77B3306 \n  E32FC3A6 2B201D94 E907F207 919C701E 919B323A 99D1BB86 5C99871D C93938A2 \n  9641C419 E02EF29A 44D6009C CDD5F5A6 8785AEB0 9010251A 789D6C96 A49FE05D \n  FA432BCD 4E2DAB87 9710927C ACA12057 AD6AD6FF 79986220 31190678 A59CF919 \n  8ABF8DFE 25D35B22 433A23B3 9BC422EC 604447EF 57448CCF 63B19FF5 459E5F66 \n  E4E7B3E9 E37E4F11 BA713934 62CD7A1A E622955D\n  \tquit\n\n\n!\n!\n!\n!\n!\n!\n!\nlicense udi pid CSR1000V sn 94A08OEI6IF\nlicense boot level ax\nflowspec\ndiagnostic bootup level minimal\n!\nspanning-tree extend system-id\nnetconf-yang ********-odm actions ACL\nnetconf-yang ********-odm actions BGP\nnetconf-yang ********-odm actions OSPF\nnetconf-yang ********-odm actions Archive\nnetconf-yang ********-odm actions IPRoute\nnetconf-yang ********-odm actions EFPStats\nnetconf-yang ********-odm actions IPSLAStats\nnetconf-yang ********-odm actions Interfaces\nnetconf-yang ********-odm actions Environment\nnetconf-yang ********-odm actions FlowMonitor\nnetconf-yang ********-odm actions MemoryStats\nnetconf-yang ********-odm actions BFDNeighbors\nnetconf-yang ********-odm actions BridgeDomain\nnetconf-yang ********-odm actions CPUProcesses\nnetconf-yang ********-odm actions LLDPNeighbors\nnetconf-yang ********-odm actions VirtualService\nnetconf-yang ********-odm actions MemoryProcesses\nnetconf-yang ********-odm actions EthernetCFMStats\nnetconf-yang ********-odm actions MPLSLDPNeighbors\nnetconf-yang ********-odm actions PlatformSoftware\nnetconf-yang ********-odm actions MPLSStaticBinding\nnetconf-yang ********-odm actions MPLSForwardingTable\nnetconf-yang\n!\nrestconf\n!\nusername admin password 0 Nms12345!\nusername testuser password 0 C1sco12345\nusername ******** privilege 15 password 0 ********\n!\nredundancy\n!\n!\n!\n!\n!\n!\n! \n!\n!\n!\n!\n!\n!\n!\n!\n!\n!\n!\n!\n! \n! \n! \n! \n! \n! \n!\n!\ninterface Loopback0\n no ip address\n!\ninterface GigabitEthernet1\n ip address 10.71.130.58 255.255.248.0\n negotiation auto\n no mop enabled\n no mop sysid\n!\ninterface GigabitEthernet2\n no ip address\n shutdown\n negotiation auto\n no mop enabled\n no mop sysid\n!\ninterface GigabitEthernet3\n no ip address\n shutdown\n negotiation auto\n no mop enabled\n no mop sysid\n!\n!\nvirtual-service csr_mgmt\n ip shared host-interface GigabitEthernet1\n activate\n!\nip forward-protocol nd\nip http server\nip http authentication local\nip http secure-server\n!\nip route 0.0.0.0 0.0.0.0 10.71.135.254\nip ssh rsa keypair-name ssh-key\nip ssh version 2\n!\nip access-list extended test-ansible\n permit ip host 1.1.1.1 any log\n permit ip host 2.2.2.2 any log\n!\n!\n!\nsnmp-server community NMS_public RO\nsnmp-server community NMS_private RW\nsnmp-server community public RO\nsnmp-server community private RW\n!\n!\n!\n!\ncontrol-plane\n!\n !\n !\n !\n !\n!\n!\n!\n!\nbanner motd ^CHello Ansible!^C\n!\nline con 0\n stopbits 1\nline vty 0 4\n transport input all\n!\ntransport type persistent webui input https-webui\n!\nnetconf ssh\n!\n!\n!\n!\n!\nend\n",
    "ansible_net_serialnum": "94A08OEI6IF",
    "ansible_net_all_ipv4_addresses": [
      "10.71.130.58"
    ],
    "ansible_net_model": null,
    "ansible_net_hostname": "CSR-2",
    "ansible_net_gather_subset": [
      "hardware",
      "default",
      "interfaces",
      "config"
    ],
    "ansible_net_interfaces": {
      "Loopback0": {
        "macaddress": null,
        "lineprotocol": "up ",
        "description": null,
        "operstatus": "up",
        "mediatype": null,
        "mtu": 1514,
        "duplex": null,
        "bandwidth": 8000000,
        "ipv4": null,
        "type": null
      },
      "GigabitEthernet1": {
        "macaddress": "0050.56a2.6a84",
        "lineprotocol": "up ",
        "description": null,
        "operstatus": "up",
        "mediatype": "RJ45",
        "mtu": 1500,
        "duplex": "Full",
        "bandwidth": 1000000,
        "ipv4": {
          "masklen": 21,
          "address": "10.71.130.58"
        },
        "type": "CSR vNIC"
      },
      "GigabitEthernet2": {
        "macaddress": "0050.56a2.aa72",
        "lineprotocol": "down ",
        "description": null,
        "operstatus": "administratively down",
        "mediatype": "RJ45",
        "mtu": 1500,
        "duplex": "Full",
        "bandwidth": 1000000,
        "ipv4": null,
        "type": "CSR vNIC"
      },
      "GigabitEthernet3": {
        "macaddress": "0050.56a2.5883",
        "lineprotocol": "down ",
        "description": null,
        "operstatus": "administratively down",
        "mediatype": "RJ45",
        "mtu": 1500,
        "duplex": "Full",
        "bandwidth": 1000000,
        "ipv4": null,
        "type": "CSR vNIC"
      }
    },
    "ansible_net_version": "16.4.1",
    "ansible_net_all_ipv6_addresses": [],
    "ansible_net_memtotal_mb": 2052243,
    "ansible_net_filesystems": [
      "bootflash:"
    ],
    "ansible_net_image": "bootflash:packages.conf",
    "ansible_net_memfree_mb": 353546
  },
  "changed": false
}
[vagrant@localhost ansible]$ 
```

#フィルタ例
jqでフィルタ。pythonスクリプトでファイルを読み込んで処理するのも楽そうです。

```json:20170323060644_CSR-2_iosfacts.txt
[vagrant@localhost ansible]$ cat file/20170323060644_CSR-2_iosfacts.txt | jq '.ansible_facts.ansible_net_interfaces.GigabitEthernet1'
{
  "macaddress": "0050.56a2.6a84",
  "lineprotocol": "up ",
  "description": null,
  "operstatus": "up",
  "mediatype": "RJ45",
  "mtu": 1500,
  "duplex": "Full",
  "bandwidth": 1000000,
  "ipv4": {
    "masklen": 21,
    "address": "10.71.130.58"
  },
  "type": "CSR vNIC"
}
```

#参考 - gather_facts
[gather_facts](http://docs.ansible.com/ansible/playbooks_variables.html#information-discovered-from-systems-facts)で取得するシステム変数の確認。

```json:local
[vagrant@localhost ansible]$ ansible localhost -m setup
localhost | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "10.0.2.15", 
            "172.28.128.3"
        ], 
        "ansible_all_ipv6_addresses": [
            "fe80::a00:27ff:fe6c:3e95", 
            "fe80::a00:27ff:fe65:cc31"
        ], 
        "ansible_architecture": "x86_64", 
        "ansible_bios_date": "12/01/2006", 
        "ansible_bios_version": "VirtualBox", 
        "ansible_cmdline": {
            "BOOT_IMAGE": "/vmlinuz-3.10.0-327.4.5.el7.x86_64", 
            "LANG": "en_GB.UTF-8", 
            "crashkernel": "auto", 
            "quiet": true, 
            "rd.lvm.lv": "centos/swap", 
            "rhgb": true, 
            "ro": true, 
            "root": "/dev/mapper/centos-root"
        }, 
        "ansible_date_time": {
            "date": "2017-03-23", 
            "day": "23", 
            "epoch": "1490251293", 
            "hour": "06", 
            "iso8601": "2017-03-23T06:41:33Z", 
            "iso8601_basic": "20170323T064133616180", 
            "iso8601_basic_short": "20170323T064133", 
            "iso8601_micro": "2017-03-23T06:41:33.616263Z", 
            "minute": "41", 
            "month": "03", 
            "second": "33", 
            "time": "06:41:33", 
            "tz": "GMT", 
            "tz_offset": "+0000", 
            "weekday": "木曜日", 
            "weekday_number": "4", 
            "weeknumber": "12", 
            "year": "2017"
        },
#以降、省略。
```

#関連記事
[AnsibleでCisco IOSの情報収集 - snmp_facts](http://qiita.com/kikuta1978/items/f0c0c408568ce8631167)
[AnsibleでCisco IOSの情報収集 - ios_commands](http://qiita.com/kikuta1978/items/66993affd83e415f2585)

以上です。