てくなべ (tekunabe)

ansible / network / automation

[Ansible] Junos の interface の状態を debug で表示する(gather_facts 編)

はじめに

以下の記事で、Junos のインターフェースの状態を取得して debug で表示するという Playbook が紹介されていました。

qiita.com

面白いネタだなと思って、拝見しました。特に、以下のディクショナリをループする書き方が参考になりました。

with_items: "{{ int_results.keys() | list }}"

自分でしたら、with_dict を使うところだったので、なるほどと思いました。

そんなことを思ったので、この記事では「Playbook紹介2~interfaceの状態確認~」の別の書き方をした Playbook をご紹介します。

この記事の書き方のほうが良いと主張するつもりはまったくなく「こんな書き方もできるんだなぁ〜」程度に思っていただければと思います。

動作確認環境


Playbook

Playbook はこんな感じです。

- name: Junos Module TEST
  hosts: junos
  gather_facts: yes   # ポイント(1)

  vars:
    ansible_python_interpreter: /usr/bin/python3
  tasks:
    - name: debug
      debug:
        msg: "admin_status : {{ admin_status }} / oper_status : {{ oper_status }}"
      with_dict: "{{ ansible_net_interfaces }}"  # ポイント(2)
      vars:
        admin_status: "{{ item.value['admin-status'] }}"    # ポイント(3)
        oper_status: "{{ item.value['oper-status']}}"

ポイント・相違点

ポイント、オリジナルとの相違点は以下のとおりです。

ポイント(1)

オリジナルでは gather_facts: no としていましたが、yes にしました。これは、Ansible 2.9 から gather_facts でネットワーク機器の facts を収集する仕様に変わったためです。代わりに、junos_facts モジュールを使うタスクは定義していません。gather_facts: yes によって暗黙的に junos_facts モジュールが利用されます。

この方式のデメリットは、Ansible コントロールノード自身の fact も収集してしまう点です。

なお、デフォルトが gather_facts: yes なので、gather_facts 自体を指定しなくても構いません。

ポイント(2)

オリジナルでは、

      with_items: "{{ int_results.keys() | list }}"

としていましたが、

      with_dict: "{{ ansible_net_interfaces }}"

にしました。

with_dict は、ディクショナリのキーの数だけループする書き方です。ループ中の item.key にキーが、item.value に値が入ります。

ループで回すディクショナリの変数は、ansible_net_interfaces にしています。 オリジナルでは、ansible_facts.net_interfaces を一旦 set_fact で別の変数 int_results に格納していますが、ansible_net_interfaces という変数も同じ内容です。set_fact をなくして、いきなり ansible_net_interfaces を指定するようにしました。このあたりは好みの問題かもしれません。

ポイント(3)

ポイント(2)で with_dict を利用した関係で、ディクショナリの値の階層の指定を item.value['admin-status'] のようにしています。

なお、admin-status のように - が含まれるキーの指定は [ ] で囲う必要があります。item.value.admin-status のように、ドット表記にしてしまうと、途中の -演算子とみなされて admin というキーを参照した結果、そんなキーないよというエラーにってしまいます。

実行結果

Playbook の実行結果です。

$ ansible-playbook -i hosts fact_test2.yml

PLAY [Junos Module TEST] ******************************************************************************************

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

ok: [junos]

TASK [debug] ******************************************************************************************************
ok: [junos] => (item={'key': 'ge-0/0/0', 'value': {'oper-status': 'down', 'admin-status': 'up', 'speed': '1000mbps', 'macaddress': '00:50:56:a2:45:a2', 'mtu': '1514', 'type': None}}) => {
    "msg": "admin_status : up / oper_status : down"
}
ok: [junos] => (item={'key': 'lc-0/0/0', 'value': {'oper-status': 'up', 'admin-status': 'up', 'speed': '800mbps', 'macaddress': 'Unspecified', 'mtu': '0', 'type': 'Unspecified'}}) => {
    "msg": "admin_status : up / oper_status : up"
}
ok: [junos] => (item={'key': 'pfe-0/0/0', 'value': {'oper-status': 'up', 'admin-status': 'up', 'speed': '800mbps', 'macaddress': 'Unspecified', 'mtu': '0', 'type': 'Unspecified'}}) => {
    "msg": "admin_status : up / oper_status : up"

...(略)...

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

なお、[WARNING]: Ignoring timeout(10) for junos_facts という警告については、以下の記事を参照してください。

[Ansible] "[WARNING]: Ignoring timeout(10) for ios_facts" の正体とタイムアウトの設定方法 - てくなべ (tekunabe)

補足

実行結果でご覧いただいたとおり、ループのたびにディクショナリの内容が表示されるのが少々うるさいですね。デバッグのときには役に立つのですが。

ok: [junos] => (item={'key': 'ge-0/0/0', 'value': {'oper-status': 'down', 'admin-status': 'up', 'speed': '1000mbps', 'macaddress': '00:50:56:a2:45:a2', 'mtu': '1514', 'type': None}}) => {
    "msg": "admin_status : up / oper_status : down"
}
...(略)...

この出力を調整したい場合は、loop_controllabel を使うと便利です。

    - name: debug
      debug:
        msg: "admin_status : {{ admin_status }} / oper_status : {{ oper_status }}"
      with_dict: "{{ ansible_net_interfaces }}"
      vars:
        admin_status: "{{ item.value['admin-status'] }}"
        oper_status: "{{ item.value['oper-status']}}"
      loop_control:                 # ポイント
        label: "{{ item.key }}"     # ポイント

このように出力を調整することで、以下のように、オリジナルと同じログになります。

ok: [junos] => (item=ge-0/0/0) => {
    "msg": "admin_status : up / oper_status : down"
}
...(略)...


おわりに

タスクとしては1つにまとめるかたちにしてみました。とはいえ、タスクが少なければいいというわけではありません。 わかりやすさ、シンプルさ、メンテンナンスしやすさ、は意外と両立させるのは難しいかもしれません。

参考

show interfaces terse | display json コマンド相当の処理を利用する場合はこちら。

tekunabe.hatenablog.jp