これは Ansible Advent Calendar 2017 の18日目の記事です。
■ やりたいこと
Ansible で Cisco IOS から複数のIPアドレスに対してpingを実行し、その結果をCSVファイルに出力します。本記事では、利用する ios_ping モジュールの説明と、 Playbookのサンプルをご紹介します。

■ ios_ping モジュールの説明
ios_ping はCisco IOS の機器から ping を実行して、ロス率やRTT値など パース して返してくれるモジュールです。Ansible 2.4 で追加されました。(本記事は Ansible 2.4.2 を前提としています)
手作業によるコマンド結果と、パースして取得できる情報の関係は以下の通りです。

主なオプション
ios_ping モジュール固有のオプションは以下の通りです。
| オプション名 | 必須/任意 | デフォルト | 説明 | 対応IOSコマンド書式 | 要特権(*1) |
|---|---|---|---|---|---|
| dest | 必須 | ping を実行する相手先のIPアドレス、ホスト名です。 | ping [dest] | 要特権 | |
| count | 任意 | 5 | ping を実行する回数です。本オプションと、IOSのpingコマンドのタイムアウト(私の環境では2秒)を考慮し、ios_ping モジュールのタスクとしてのタイムアウト( timeout オプション: デフォルト10秒) を設定する必要があります。 |
ping [dest] repeat [count] | 要特権 |
| source | 任意 | 送信元の指定です。 | ping [dest] source [source] | 要特権 | |
| state | 任意 | present | 想定するping結果の指定です。 想定結果が成功なら present、失敗なら absent を指定します。成功、失敗の基準は公式ドキュメントに記載されていませんが、ios_ping.pyのコードを見ると「ロス率が100%未満→成功」「ロス率が100%→失敗」ということが分かります。 |
要特権 | |
| vrf | 任意 | default | 利用するVRFの指定です。 | ping vrf [vrf] [dest] | 要特権 |
要特権(*1)と書かれているオプションを利用するには、IOSへログインするユーザーに特権が必要です。手動実行と同じ事情です。- 認証系のオプションである
provider等は 他のios_command等のモジュールと共通です。 - 全オプションは ios_ping モジュール公式ドキュメント を参照して下さい。
■ ping結果をCSV出力するためのPlaybookなど
・Playbook
Playbook 本体です。
--- - hosts: ios # インベントリファイルにて10.0.0.1を定義済み gather_facts: no connection: local tasks: - name: ping ios_ping: dest: "{{ item }}" count: 5 # default provider: "{{ cli }}" with_items: - 192.168.1.1 - 192.168.1.2 - 192.168.1.3 - 192.168.1.4 - 192.168.1.5 - 192.168.1.6 - 192.168.1.7 - 192.168.1.8 - 192.168.1.9 - 192.168.1.10 ignore_errors: yes register: result - name: output csv file template: src: ./template_ping_result.txt dest: "./ping_from_{{ inventory_hostname }}_result.csv" vars: cli: host: "{{ inventory_hostname }}" timeout: 15 # (5 * 2) + margin username: testuser password: testpassword authorize: yes auth_pass: testpassword
Playbook の補足説明
with_itemsを利用して、複数の宛先へのping結果を取得するようにしています。必要に応じてパラメータ化して下しさい。stateオプションは省略しているため、成功(ロス率100%未満)を想定しています。もしpingが失敗した場合は、playbook中のタスクとしてfailed扱いになります。- 今回は想定外の
stateになった場合の挙動も確認しつつ、タスクを続行したかったため、少々乱暴ですがignore_errors: yesを指定しています。 count: 5(デフォルトと同じ)にしているため、IOS側のpingコマンド仕様のタイムアウト2秒を考慮すると、ロス率100%の宛先相手の場合pingが完了に10秒かかります。タスクとしてのtimeuoutオプションのデフォルトも10秒のため、pingが完了する前にタスクとしてタイムアウトしています。この問題の対策として「countオプション × pingコマンドタイムアウト = 10秒」にさらに余裕を加えて、ios_pingモジュールのtimeoutオプションを15としています。
・テンプレート
ping結果をCSVファイルに整形するするためのテンプレートです。いろいろカスタマイズできます。
"dest","packet_loss","packets_rx","packets_tx","rtt_avg","rtt_max","rtt_min","msg"
{% for r in result['results'] %}
"{{r['item'] }}","{{ r['packet_loss'] }}",{{ r['packets_rx'] }},{{ r['packets_tx'] }},{{ r['rtt']['avg'] }},{{ r['rtt']['max']}},{{ r['rtt']['min'] }},"{{ r['msg'] | default('') }}"
{% endfor %}
テンプレートの補足説明
- Playbook 中で 変数
resultsとして取得した複数のping結果を、1宛先ごとにループしています。 msgは想定外のsteteの時のみ返ってくる値です。そのため、想定通りのstateの場合にmsgを出力しようとするとエラーになっていまいます。エラー対策として、defaultフィルターを利用して、返ってこなかった場合に空文字になるようにしています。
■ 実行その1(全OK)
すべての宛先のping結果が想定通りの state の場合です。
・playbookの実行
[vagrant@centos7 vagrant]$ ansible-playbook -i hosts ping.yml PLAY [ios] ********************************************************************* TASK [ping] ******************************************************************** ok: [10.0.0.1] => (item=192.168.1.1) ok: [10.0.0.1] => (item=192.168.1.2) ok: [10.0.0.1] => (item=192.168.1.3) ok: [10.0.0.1] => (item=192.168.1.4) ok: [10.0.0.1] => (item=192.168.1.5) ok: [10.0.0.1] => (item=192.168.1.6) ok: [10.0.0.1] => (item=192.168.1.7) ok: [10.0.0.1] => (item=192.168.1.8) ok: [10.0.0.1] => (item=192.168.1.9) ok: [10.0.0.1] => (item=192.168.1.10) TASK [output csv file] ********************************************************* changed: [10.0.0.1] PLAY RECAP ********************************************************************* 10.0.0.1 : ok=2 changed=1 unreachable=0 failed=0
・CSV出力結果
[vagrant@centos7 vagrant]$ cat ping_from_10.0.0.1_result.csv "dest","packet_loss","packets_rx","packets_tx","rtt_avg","rtt_max","rtt_min","msg" "192.168.1.1","0%",5,5,2,9,1,"" "192.168.1.2","0%",5,5,2,9,1,"" "192.168.1.3","0%",5,5,8,9,8,"" "192.168.1.4","0%",5,5,7,9,1,"" "192.168.1.5","0%",5,5,6,9,1,"" "192.168.1.6","0%",5,5,8,9,8,"" "192.168.1.7","0%",5,5,8,9,8,"" "192.168.1.8","0%",5,5,7,9,1,"" "192.168.1.9","0%",5,5,7,9,1,"" "192.168.1.10","0%",5,5,8,9,8,""
■ 実行その2(一部NG)
一部宛先のping結果が想定外の state の場合です。
・Playbook実行
[vagrant@centos7 vagrant]$ ansible-playbook -i hosts ping.yml
PLAY [ios] *********************************************************************
TASK [ping] ********************************************************************
ok: [10.0.0.1] => (item=192.168.1.1)
failed: [10.0.0.1] (item=192.168.1.2) => {"changed": false, "commands": ["ping 192.168.1.99 repeat 5"], "item": "192.168.1.99", "msg": "Ping failed unexpectedly", "packet_loss": "100%", "packets_rx": 0, "packets_tx": 5, "rtt": {"avg": null, "max": null, "min": null}}
ok: [10.0.0.1] => (item=192.168.1.3)
ok: [10.0.0.1] => (item=192.168.1.4)
ok: [10.0.0.1] => (item=192.168.1.5)
ok: [10.0.0.1] => (item=192.168.1.6)
ok: [10.0.0.1] => (item=192.168.1.7)
ok: [10.0.0.1] => (item=192.168.1.8)
ok: [10.0.0.1] => (item=192.168.1.9)
ok: [10.0.0.1] => (item=192.168.1.10)
...ignoring
TASK [temp] ********************************************************************
changed: [10.0.0.1]
PLAY RECAP *********************************************************************
10.0.0.1 : ok=2 changed=1 unreachable=0 failed=0
想定外だった宛先に対するpingのタスクは failed になります。
・CSV出力結果
以下の通り、疎通が取れる想定だった宛先に対して、ロス率100%だった場合は、msg が Ping failed unexpectedly となります。
[vagrant@centos7 vagrant]$ cat ping_from_10.0.0.1_result.csv "dest","packet_loss","packets_rx","packets_tx","rtt_avg","rtt_max","rtt_min","msg" "192.168.1.1","0%",5,5,2,9,1,"" "192.168.1.2",”100%",0,5,,,,"Ping failed unexpectedly" "192.168.1.3","0%",5,5,8,9,8,"" "192.168.1.4","0%",5,5,7,9,1,"" "192.168.1.5","0%",5,5,6,9,1,"" "192.168.1.6","0%",5,5,8,9,8,"" "192.168.1.7","0%",5,5,8,9,8,"" "192.168.1.8","0%",5,5,7,9,1,"" "192.168.1.9","0%",5,5,7,9,1,"" "192.168.1.10","0%",5,5,8,9,8,""
なお、疎通が取れない想定だった宛先に対して、ロス率100%未満 の場合は、msg が Ping succeeded unexpectedly となります。
■ まとめ
Ansible の ios_ping モジュールと template モジュール利用して、Cisco IOS からの ping 結果を CSV 出力してみました。
count と timeout の関係や、「何をもって成功/失敗とするか」あたりがポイントです。
また、今回はping実行ホスト1台につき1つのCSVファイルを生成しましたが、作り方次第では1つのファイルにまとめることも可能かと思います。
もし、今回のような内容をしたい場合に、本記事が参考になれば幸いです。