てくなべ (tekunabe)

ansible / network / automation

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

はじめに

以前の記事で、gather_facts を利用して Junos のインターフェースの状態を取得して debug で表示するという Playbook をご紹介しました。

tekunabe.hatenablog.jp

今回は普通に show interfaces terse コマンドを利用します。ただし、せっかく JSON で表示してくれるバージョンの Junos であれば、display json を使うのも手です。

この記事では、show interfaces terse | display json コマンド相当の処理を利用します。

動作確認環境


Playbook

Playbook はこんな感じです。

- name: Junos Module TEST
  hosts: junos
  gather_facts: no      # ポイント(1)
  vars:
    ansible_python_interpreter: /usr/bin/python3
  tasks:
    - name: show
      junos_command:
        commands:
          - show interfaces terse 
        display: json               # ポイント(2)
      register: result

    - name: debug
      debug:
        msg: "admin_status : {{ admin_status }} / oper_status : {{ oper_status }}"
      loop: "{{ result.stdout[0]['interface-information'][0]['physical-interface'] }}"  # ポイント(3)
      vars:
        admin_status: "{{ item['admin-status'][0]['data'] }}"      # ポイント(4)
        oper_status: "{{ item['oper-status'][0]['data'] }}"

ポイント・相違点

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

ポイント(1)

gather_facts ではなく、show コマンドを利用するため、無効にします。

ポイント(2)

junos_command モジュールを利用して、show interfaces terse コマンドを実行します。

json で結果を取得したいので、display: json を指定します。

ポイント(3)

show interfaces terse コマンドの結果を json で取得して、物理インターフェースの情報がある構造を指定します。 ここまで指定すると、各インターフェースの情報がリストで格納されているので、witth_dict ではなく普通に loop を使います。

機種は設定によっては、ここの指定方法が変わるかもしれません。

なお、json の全内容は以下の通りです。(1000行以上あるのご注意)

クリック指定開く

{
    "interface-information": [
        {
            "physical-interface": [
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "ge-0/0/0"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "down"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "logical-interface": [
                        {
                            "address-family": [
                                {
                                    "address-family-name": [
                                        {
                                            "data": "vpls"
                                        }
                                    ]
                                }
                            ],
                            "admin-status": [
                                {
                                    "data": "up"
                                }
                            ],
                            "filter-information": [
                                {}
                            ],
                            "name": [
                                {
                                    "data": "lc-0/0/0.32769"
                                }
                            ],
                            "oper-status": [
                                {
                                    "data": "up"
                                }
                            ]
                        }
                    ],
                    "name": [
                        {
                            "data": "lc-0/0/0"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "logical-interface": [
                        {
                            "address-family": [
                                {
                                    "address-family-name": [
                                        {
                                            "data": "inet"
                                        }
                                    ]
                                },
                                {
                                    "address-family-name": [
                                        {
                                            "data": "inet6"
                                        }
                                    ]
                                }
                            ],
                            "admin-status": [
                                {
                                    "data": "up"
                                }
                            ],
                            "filter-information": [
                                {}
                            ],
                            "name": [
                                {
                                    "data": "pfe-0/0/0.16383"
                                }
                            ],
                            "oper-status": [
                                {
                                    "data": "up"
                                }
                            ]
                        }
                    ],
                    "name": [
                        {
                            "data": "pfe-0/0/0"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "logical-interface": [
                        {
                            "address-family": [
                                {
                                    "address-family-name": [
                                        {
                                            "data": "inet"
                                        }
                                    ]
                                }
                            ],
                            "admin-status": [
                                {
                                    "data": "up"
                                }
                            ],
                            "filter-information": [
                                {}
                            ],
                            "name": [
                                {
                                    "data": "pfh-0/0/0.16383"
                                }
                            ],
                            "oper-status": [
                                {
                                    "data": "up"
                                }
                            ]
                        },
                        {
                            "address-family": [
                                {
                                    "address-family-name": [
                                        {
                                            "data": "inet"
                                        }
                                    ]
                                }
                            ],
                            "admin-status": [
                                {
                                    "data": "up"
                                }
                            ],
                            "filter-information": [
                                {}
                            ],
                            "name": [
                                {
                                    "data": "pfh-0/0/0.16384"
                                }
                            ],
                            "oper-status": [
                                {
                                    "data": "up"
                                }
                            ]
                        }
                    ],
                    "name": [
                        {
                            "data": "pfh-0/0/0"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "ge-0/0/1"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "down"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "ge-0/0/2"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "down"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "ge-0/0/3"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "down"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "ge-0/0/4"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "down"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "ge-0/0/5"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "down"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "ge-0/0/6"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "down"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "ge-0/0/7"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "down"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "cbp0"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "demux0"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "dsc"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "logical-interface": [
                        {
                            "address-family": [
                                {
                                    "address-family-name": [
                                        {
                                            "data": "inet"
                                        }
                                    ],
                                    "interface-address": [
                                        {
                                            "ifa-local": [
                                                {
                                                    "attributes": {
                                                        "junos:emit": "emit"
                                                    },
                                                    "data": "10.0.0.4/8"
                                                }
                                            ]
                                        },
                                        {
                                            "ifa-local": [
                                                {
                                                    "attributes": {
                                                        "junos:emit": "emit"
                                                    },
                                                    "data": "128.0.0.1/2"
                                                }
                                            ]
                                        },
                                        {
                                            "ifa-local": [
                                                {
                                                    "attributes": {
                                                        "junos:emit": "emit"
                                                    },
                                                    "data": "128.0.0.4/2"
                                                }
                                            ]
                                        }
                                    ]
                                },
                                {
                                    "address-family-name": [
                                        {
                                            "data": "inet6"
                                        }
                                    ],
                                    "interface-address": [
                                        {
                                            "ifa-local": [
                                                {
                                                    "attributes": {
                                                        "junos:emit": "emit"
                                                    },
                                                    "data": "fe80::250:56ff:fea2:f74b/64"
                                                }
                                            ]
                                        },
                                        {
                                            "ifa-local": [
                                                {
                                                    "attributes": {
                                                        "junos:emit": "emit"
                                                    },
                                                    "data": "fec0::a:0:0:4/64"
                                                }
                                            ]
                                        }
                                    ]
                                },
                                {
                                    "address-family-name": [
                                        {
                                            "data": "tnp"
                                        }
                                    ],
                                    "interface-address": [
                                        {
                                            "ifa-local": [
                                                {
                                                    "attributes": {
                                                        "junos:emit": "emit"
                                                    },
                                                    "data": "0x4"
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ],
                            "admin-status": [
                                {
                                    "data": "up"
                                }
                            ],
                            "filter-information": [
                                {}
                            ],
                            "name": [
                                {
                                    "data": "em1.0"
                                }
                            ],
                            "oper-status": [
                                {
                                    "data": "up"
                                }
                            ]
                        }
                    ],
                    "name": [
                        {
                            "data": "em1"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "esi"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "fti0"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "fti1"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "fti2"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "fti3"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "fti4"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "fti5"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "fti6"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "fti7"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "logical-interface": [
                        {
                            "address-family": [
                                {
                                    "address-family-name": [
                                        {
                                            "data": "inet"
                                        }
                                    ],
                                    "interface-address": [
                                        {
                                            "ifa-local": [
                                                {
                                                    "attributes": {
                                                        "junos:emit": "emit"
                                                    },
                                                    "data": "100.123.1.0/16"
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ],
                            "admin-status": [
                                {
                                    "data": "up"
                                }
                            ],
                            "filter-information": [
                                {}
                            ],
                            "name": [
                                {
                                    "data": "fxp0.0"
                                }
                            ],
                            "oper-status": [
                                {
                                    "data": "up"
                                }
                            ]
                        }
                    ],
                    "name": [
                        {
                            "data": "fxp0"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "gre"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "ipip"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "irb"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "logical-interface": [
                        {
                            "address-family": [
                                {
                                    "address-family-name": [
                                        {
                                            "data": "inet"
                                        }
                                    ],
                                    "interface-address": [
                                        {
                                            "ifa-local": [
                                                {
                                                    "attributes": {
                                                        "junos:emit": "emit"
                                                    },
                                                    "data": "128.0.0.127/2"
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ],
                            "admin-status": [
                                {
                                    "data": "up"
                                }
                            ],
                            "filter-information": [
                                {}
                            ],
                            "name": [
                                {
                                    "data": "jsrv.1"
                                }
                            ],
                            "oper-status": [
                                {
                                    "data": "up"
                                }
                            ]
                        }
                    ],
                    "name": [
                        {
                            "data": "jsrv"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "logical-interface": [
                        {
                            "address-family": [
                                {
                                    "address-family-name": [
                                        {
                                            "data": "inet"
                                        }
                                    ],
                                    "interface-address": [
                                        {
                                            "ifa-destination": [
                                                {
                                                    "attributes": {
                                                        "junos:emit": "emit"
                                                    },
                                                    "data": "0/0"
                                                }
                                            ],
                                            "ifa-local": [
                                                {
                                                    "data": "127.0.0.1"
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ],
                            "admin-status": [
                                {
                                    "data": "up"
                                }
                            ],
                            "filter-information": [
                                {}
                            ],
                            "name": [
                                {
                                    "data": "lo0.16384"
                                }
                            ],
                            "oper-status": [
                                {
                                    "data": "up"
                                }
                            ]
                        },
                        {
                            "address-family": [
                                {
                                    "address-family-name": [
                                        {
                                            "data": "inet"
                                        }
                                    ]
                                }
                            ],
                            "admin-status": [
                                {
                                    "data": "up"
                                }
                            ],
                            "filter-information": [
                                {}
                            ],
                            "name": [
                                {
                                    "data": "lo0.16385"
                                }
                            ],
                            "oper-status": [
                                {
                                    "data": "up"
                                }
                            ]
                        }
                    ],
                    "name": [
                        {
                            "data": "lo0"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "lsi"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "mtun"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "pimd"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "pime"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "pip0"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "pp0"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "rbeb"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "tap"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                },
                {
                    "admin-status": [
                        {
                            "data": "up"
                        }
                    ],
                    "name": [
                        {
                            "data": "vtep"
                        }
                    ],
                    "oper-status": [
                        {
                            "data": "up"
                        }
                    ]
                }
            ]
        }
    ]
}

ポイント(4)

json の構造に沿って、インターフェース名と各状態をタスク変数(ループごとに更新される)に格納します。

実行結果

Playbook の実行結果です。

$ ansible-playbook -i hosts fact_test2.yml

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

TASK [show] **************************************************************************************************************************
ok: [vmx]

TASK [debug] *************************************************************************************************************************
ok: [vmx] => (item={'name': [{'data': 'ge-0/0/0'}], 'admin-status': [{'data': 'up'}], 'oper-status': [{'data': 'down'}]}) => {
    "msg": "admin_status : up / oper_status : down"
}
ok: [vmx] => (item={'name': [{'data': 'lc-0/0/0'}], 'admin-status': [{'data': 'up'}], 'oper-status': [{'data': 'up'}], 'logical-interface': [{'name': [{'data': 'lc-0/0/0.32769'}], 'admin-status': [{'data': 'up'}], 'oper-status': [{'data': 'up'}], 'filter-information': [{}], 'address-family': [{'address-family-name': [{'data': 'vpls'}]}]}]}) => {
    "msg": "admin_status : up / oper_status : up"
}
ok: [vmx] => (item={'name': [{'data': 'pfe-0/0/0'}], 'admin-status': [{'data': 'up'}], 'oper-status': [{'data': 'up'}], 'logical-interface': [{'name': [{'data': 'pfe-0/0/0.16383'}], 'admin-status': [{'data': 'up'}], 'oper-status': [{'data': 'up'}], 'filter-information': [{}], 'address-family': [{'address-family-name': [{'data': 'inet'}]}, {'address-family-name': [{'data': 'inet6'}]}]}]}) => {
    "msg": "admin_status : up / oper_status : up"
}

...(略)...

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

補足

ループごとに表示される変数の値を調整したい場合は、loop_controllabel を使うと便利です。

# ...(略)
    - name: debug
      debug:
        msg: "admin_status : {{ admin_status }} / oper_status : {{ oper_status }}"
      loop: "{{ result.stdout[0]['interface-information'][0]['physical-interface'] }}" 
      vars:
        admin_status: "{{ item['admin-status'][0]['data'] }}"
        oper_status: "{{ item['oper-status'][0]['data'] }}"
      loop_control:           # ポイント
        label: "{{ item['name'][0]['data'] }}"      # ポイント

結果

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


おわりに

状態を取得するだけでも色々な方法があることが分かりますね。

他にも TextFSM をパーサーを利用する方法もあります。

参考

qiita.com tekunabe.hatenablog.jp

[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

[Ansible] 最初の文字だけ大文字に変換する capitalize フィルター

capitalize フィルターは、最初の文字だけ大文字に変換するものです。

Ansible の公式ドキュメントの Filter ページには載っていませんが、Jinja2 のドキュメントに載っています。

以下に、使用例を紹介します。

---
- hosts: localhost
  gather_facts: false

  tasks:
    - debug:
        msg:
          - "{{ 'abc' | capitalize }}"               # Abc
          - "{{ 'ABC' | capitalize }}"               # Abc
          - "{{ 'this is a kingyo.' | capitalize }}" # This is a kingyo.
          - "{{ 'THIS IS A KINGYO.' | capitalize }}" # This is a kingyo.

ネットワーク設定自動化で、いつ、何を確認するか(JANOG45 の Fastly さんの発表から学ぶ)

はじめに

JANOG45 Meeting in Sapporo で、Fastly の土屋さんから「急成長を支えるFastlyスケーラブル・グローバルネットワーク」という発表がありました。

www.janog.gr.jp

シンプルさを追及した設計や、自動化の話があって大変興味深いものでした。

なかでも私が注目したのが、設定自動化の作業フロー内で「いつ、何を確認するか」です。(該当スライドは P15〜、動画は 22:30〜)

この記事では、Fastly さんの事例とそこから学んだことをまとめます。主に、実機に設定を反映する前の段階にフォーカスします。

なお、当日は残念ながらプログラムに参加できず、資料アーカイブ動画(2020/03/09 12:00 までの期間限定公開)togetter を拝見しました。


■ Fastly さんの場合

発表内の設定自動化部分を中心にまとめます。発表の内容をベースにしていますが、若干自己解釈が含まれています。

自動化の背景

  • 1年に10拠点くらい増える、数年後に倍になっているかもしれない
  • とはいえ、ネットワークエンジニアを倍に増やすわけにはいかない
  • スケーラブルにするために自動化
  • トポロジーコンフィギュレーションがシンプル、標準化しやすいので自動化もしやすい

自動化していること

Network Configuration Workflow

  • 新しくピアを張る設定作業の作業フローの話
  • 大まかな工程は、Day0 は作業準備期間、Day1 は作業日当日

f:id:akira6592:20200219164550p:plain
急成長を支えるFastlyスケーラブルグローバルネットワーク(P15)から引用

【Day0】 作業準備期間

  • 作業者が手元で作業情報をアップデートし、Pull Request を出す
    • 作業情報例
      • どのスイッチ、ポートでどことピアを張るか、IPアドレス設定、BGPのパラメーター
  • CI テスト が実行される
    • システムが確認すること
      • バリデーションテスト
  • 承認者が Pull Request の内容をレビューして問題が無ければデータストアにマージする
    • 人が確認すること
      • 設定の意図が正しいこと
      • 正しいPOPであること、クラッシュ(既知の不具合?)しないこと
  • Ansibly (Ansible の内製ラッパーツール)で Dry-run を実行
    • パラメーターファイルをもとにコンフィグを生成
    • そのコンフィグを機器に流す、ただし commit しない
    • システムが確認すること
      • ファイルに問題がないか
      • 設定に矛盾がないか
      • ちゃんと投入できるコンフィグレーションか
        • 実際の機器に(commitせずに)投入することで確認できる

【Day1】 作業日当日

  • 準備段階で正しいコンフィグができているので、あとはコマンドを叩いて、実際にピアやキャッシュを設定する
  • 設定後はネットワークの正常性(トラフィック変化、意図しないアラートがでていないか、など)を人が確認


■ 自動化において、いつ、何を確認するか

前項で、Fastly さんでの事例をまとめました。次は、そこから学んだことや、今までなんとなく頭の中で考えていたことを書き連ねます。(事例とは直接関係ありません)

観点

何のための確認か

  • いつ
  • だれ(なにが)が
  • 何を確認すれば
  • 何を防げるのか

何を確認するか

  • 構文
    • コンフィグが構文的に正しいこと
    • 機械的に判断するのが得意
    • 実際の機器に投入して commit 寸前でとめてチェックするのが精度が高い
      • 人がそれらしく作ったコンフィグでも実際の機器に投入するとエラーになることがある
      • 別途コンフィグの構文チェックができる機器もある(Cumulus + Ansible の例
    • コンフィグ投入で即反映するタイプ(commit がない)機器では難しい
      • 独自のロジックを作りこんで、事前にチェックはできる
      • ただ、精度はチェックロジックの実装依存になる
  • 設計
    • 設計が正しいこと
    • 人が判断するのが得意
      • というより機械が苦手
      • 機械的に判断できることは限定的、または相応の作りこみが必要
  • 振る舞い
    • 各種 show コマンド、ping、traceroute コマンドで状態確認
      • 機械的に判断するためには、コマンド結果を構造化データ(JSONなど)で取得できるのが良い
    • 実機に設定を反映した後のタイミング
      • Batfish のようなツールで、ある程度事前にチェックできることも

いつ、何をチェックするか(できるか)

想定フロー

以下のようフローを想定します。

f:id:akira6592:20200219210530p:plain
想定フロー

方針

基本的には以下のような方針になるのかなと考えています。

  • 設計の正しさは、人が確認
  • 構文の正しさは、機械(自動化システムやネットワーク機器)が確認

フェーズごとの確認のしやすさ

フェーズ 主体 設計チェック 構文チェック
(1) パラメーター・コンフィグ作成 【◯】 設計に集中してパラメーターを作成できる。ただし作成者の思い込みや、環境不備によるミスは気が付きにくい。 【△】 作成者の環境依存。ローカルの開発環境で lint 的なものを動かしていれば有効
(2) CI 機械 【△】 設計意図をくみ取ったり、ネットワーク全体としての妥当性を判断するのは難しく、作り込みが必要。コンフィグの場合は、予めパースする必要がある 【◯】 スキーマチェック。コンフィグの場合は、予めパースする必要がある
(3) レビュー 【◯】 作成者の思い込みよるミスを防ぎやすい 【△】 机上チェックになりがちで難しい
(4) Dry-run 機械 【×】 ネットワーク機器自身に設計意図は判断できない 【◯】 機器が実際に解釈した結果を得られる

補足

上記でいう「パラメーター」は、設定値を構造化データフォーマットで定義したものを指します。機器に投入できるコンフィグを生成する元ネタになります。

interfaces:
  - name: GigabitEthernet1/0/1
    description: hogehoge
    enalbed: true

一方の「コンフィグ」とは機器に投入できるコンフィグそのものを示します。

interface GigabitEthernet1/0/1
  description hogehoge
  no shutdown


さいごに

1つの事例をきっかけにして、いつ、何を確認するかをまとめました。

うまく整理、言語化できていないところもあるかと思いますので、お気づきの点があれば@akira6592 までコメントいただければ幸いです。

これを書いている時に、人が得意なこと・苦手なこと、機械が得意なこと・苦手なことを少し深堀りしたくなったので、まとめたら別途記事を書きます。

参考

www.intentionet.com tekunabe.hatenablog.jp

その他参加した JANGO45 のプログラム

tekunabe.hatenablog.jp

[Ansible] 見やすい json に整形するには to_nice_json フィルターが nice で便利

はじめに

Ansible には、テキストデータの内容を整形するための多数のフィルターがあります。

json 形式に変換するフィルターもいくつかあり、そのなかで to_nice_json フィルターは、人にとって見やすく整形するのにとても便利です。

公式ドキュメントでは出力例の記載がないので、イマイチありがたみが分からないかもしれません。

この記事では、簡単なサンプルを利用してご紹介します。

f:id:akira6592:20200215182502p:plain:w400
こんなイメージ


サンプル

Playbook の作成

処理内容は以下の通りです。

  • uri モジュールで、Google Public DNSDNS-over-HTTPS (DoH)を利用して www.ansible.com の Aレコードのデータを JSON で取得
  • 結果を、整形なし、to_nice_yaml フィルターで整形、のそれぞれのパターンでファイルに出力
- hosts: localhost
  gather_facts: no
  connection: local

  tasks:
    - name: get json
      uri:
        url:  https://dns.google.com/resolve?name=www.ansible.com&type=A
      register: result

    - name: raw json
      copy:
        content: "{{ result }}"
        dest: raw.json       # 整形なしで出力
    
    - name: nice json
      copy:
        content: "{{ result | to_nice_json }}"
        dest: nice_json.json  # to_nice_json 適用結果を出力

Playbook 実行

Playbook を実行します。

$ ansible-playbook -i localhost, nice.yml 

PLAY [localhost] **************************************************************************************************

TASK [get json] ***************************************************************************************************
ok: [localhost]

TASK [raw json] ***************************************************************************************************
changed: [localhost]

TASK [nice json] **************************************************************************************************
changed: [localhost]

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

特に整形せずに出力した raw.json は以下のようになります。データフォーマットとしては正しいですが、改行がないので見にくいですね。

{"redirected": false, "url": "https://dns.google.com/resolve?name=www.ansible.com&type=A", "status": 200, "strict_transport_security": "max-age=31536000; includeSubDomains; preload", "access_control_allow_origin": "*", "date": "Sat, 15 Feb 2020 08:48:47 GMT", "expires": "Sat, 15 Feb 2020 08:48:47 GMT", "cache_control": "private, max-age=119", "content_type": "application/x-javascript; charset=UTF-8", "server": "HTTP server (unknown)", "x_xss_protection": "0", "x_frame_options": "SAMEORIGIN", "alt_svc": "quic=\":443\"; ma=2592000; v=\"46,43\",h3-Q050=\":443\"; ma=2592000,h3-Q049=\":443\"; ma=2592000,h3-Q048=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000", "accept_ranges": "none", "vary": "Accept-Encoding", "connection": "close", "cookies_string": "", "cookies": {}, "msg": "OK (unknown bytes)", "elapsed": 0, "changed": false, "json": {"Status": 0, "TC": false, "RD": true, "RA": true, "AD": false, "CD": false, "Question": [{"name": "www.ansible.com.", "type": 1}], "Answer": [{"name": "www.ansible.com.", "type": 5, "TTL": 299, "data": "330046g46.secure0032.hubspot.net."}, {"name": "330046g46.secure0032.hubspot.net.", "type": 5, "TTL": 299, "data": "330046.group46.sites.hubspot.net."}, {"name": "330046.group46.sites.hubspot.net.", "type": 5, "TTL": 119, "data": "group46.sites.hscoscdn40.net."}, {"name": "group46.sites.hscoscdn40.net.", "type": 1, "TTL": 299, "data": "104.17.114.180"}, {"name": "group46.sites.hscoscdn40.net.", "type": 1, "TTL": 299, "data": "104.17.115.180"}, {"name": "group46.sites.hscoscdn40.net.", "type": 1, "TTL": 299, "data": "104.17.112.180"}, {"name": "group46.sites.hscoscdn40.net.", "type": 1, "TTL": 299, "data": "104.17.116.180"}, {"name": "group46.sites.hscoscdn40.net.", "type": 1, "TTL": 299, "data": "104.17.113.180"}], "Comment": "Response from 173.245.59.182."}, "failed": false}

一方、to_nice_json フィルターを適用した nice_json.json は以下のようになります。見やすいです。

{
    "accept_ranges": "none",
    "access_control_allow_origin": "*",
    "alt_svc": "quic=\":443\"; ma=2592000; v=\"46,43\",h3-Q050=\":443\"; ma=2592000,h3-Q049=\":443\"; ma=2592000,h3-Q048=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000",
    "cache_control": "private, max-age=119",
    "changed": false,
    "connection": "close",
    "content_type": "application/x-javascript; charset=UTF-8",
    "cookies": {},
    "cookies_string": "",
    "date": "Sat, 15 Feb 2020 08:48:47 GMT",
    "elapsed": 0,
    "expires": "Sat, 15 Feb 2020 08:48:47 GMT",
    "failed": false,
    "json": {
        "AD": false,
        "Answer": [
            {
                "TTL": 299,
                "data": "330046g46.secure0032.hubspot.net.",
                "name": "www.ansible.com.",
                "type": 5
            },
            {
                "TTL": 299,
                "data": "330046.group46.sites.hubspot.net.",
                "name": "330046g46.secure0032.hubspot.net.",
                "type": 5
            },
            {
                "TTL": 119,
                "data": "group46.sites.hscoscdn40.net.",
                "name": "330046.group46.sites.hubspot.net.",
                "type": 5
            },
            {
                "TTL": 299,
                "data": "104.17.114.180",
                "name": "group46.sites.hscoscdn40.net.",
                "type": 1
            },
            {
                "TTL": 299,
                "data": "104.17.115.180",
                "name": "group46.sites.hscoscdn40.net.",
                "type": 1
            },
            {
                "TTL": 299,
                "data": "104.17.112.180",
                "name": "group46.sites.hscoscdn40.net.",
                "type": 1
            },
            {
                "TTL": 299,
                "data": "104.17.116.180",
                "name": "group46.sites.hscoscdn40.net.",
                "type": 1
            },
            {
                "TTL": 299,
                "data": "104.17.113.180",
                "name": "group46.sites.hscoscdn40.net.",
                "type": 1
            }
        ],
        "CD": false,
        "Comment": "Response from 173.245.59.182.",
        "Question": [
            {
                "name": "www.ansible.com.",
                "type": 1
            }
        ],
        "RA": true,
        "RD": true,
        "Status": 0,
        "TC": false
    },
    "msg": "OK (unknown bytes)",
    "redirected": false,
    "server": "HTTP server (unknown)",
    "status": 200,
    "strict_transport_security": "max-age=31536000; includeSubDomains; preload",
    "url": "https://dns.google.com/resolve?name=www.ansible.com&type=A",
    "vary": "Accept-Encoding",
    "x_frame_options": "SAMEORIGIN",
    "x_xss_protection": "0"
}

応用編

to_nice_json フィルターはインデント数の指定もできます。デフォルトは4個です。

例えば、2個にする場合は、以下のように指定します。

        content: "{{ result | to_nice_json(indent=2) }}"

結果

{
  "accept_ranges": "none",
  "access_control_allow_origin": "*",
  "alt_svc": "quic=\":443\"; ma=2592000; v=\"46,43\",h3-Q050=\":443\"; ma=2592000,h3-Q049=\":443\"; ma=2592000,h3-Q048=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000",
  "cache_control": "private, max-age=119",
  "changed": false,
  // ...(略)...
}


さいごに

json 以外にも yaml 関連、その他様々なフィルターが用意されているので、たまに眺めてみると欲しかったフィルターが見つかるかもしれません。

docs.ansible.com

[Ansible] パターン表記したインベントリの確認は ansible-inventory コマンドが便利

はじめに

Ansible のインベントリファイルでは、効率よく定義するためにパターン表記ができます。

例えば、

web_[1:3]

web_1
web_2
web_3

と同じです。

この様にパターン表記を利用した場合、うまく解釈されるかどうか事前に確認したくなるのではないでしょうか。

ansible-inventory コマンドを利用すると確認できます。この記事では、簡単なサンプルをご紹介します。

  • 動作確認環境
    • Ansible 2.9.4

サンプル

インベントリの用意

いろいろなパターン表記を含めたインベントリファイルを用意します。

  • inventory.ini
[web]
web_[1:3]
web_[01:03]
10.0.0.[101:103]

[db]
db_[a:c]
db_[X:Z]

[general]
gen_[a:b][01:02]

ansible-inventory コマンドの実行

ansible-inventory コマンドの -i オプションでインベントリファイルを指定し、--list オプションでリスト表示を指定します。

$ ansible-inventory -i inventory.ini --list
{
    "_meta": {
        "hostvars": {}
    },
    "all": {
        "children": [
            "db",
            "general",
            "ungrouped",
            "web"
        ]
    },
    "db": {
        "hosts": [
            "db_X",
            "db_Y",
            "db_Z",
            "db_a",
            "db_b",
            "db_c"
        ]
    },
    "general": {
        "hosts": [
            "gen_a01",
            "gen_a02",
            "gen_b01",
            "gen_b02"
        ]
    },
    "web": {
        "hosts": [
            "10.0.0.101",
            "10.0.0.102",
            "10.0.0.103",
            "web_01",
            "web_02",
            "web_03",
            "web_1",
            "web_2",
            "web_3"
        ]
    }
}

色々なパターン表記が展開されたことが分かります。


さいごに

ansible-inventory コマンドは他にも、グループの親子関係を表示する --graph オプションがあったり、ダイナミックインベントリを指定する機能もあります。

Playbook を用意、実行する前に意図したインベントリかどうか確認するのにとても便利です。

参考

[Ansible] set_fact の利用を減らしたい時に考えること

はじめに

set_fact モジュールは、Playbook 内のタスクとして、新たな変数を定義できるモジュールです。

便利といえば便利なのですが、プログラムでいう変数の代入のようなことをタスクで実現させるには、少々大げさに感じることがあります。 set_fact モジュールにしかできない変数の定義方法もありますが、簡単な定義であれば他の方法でも定義できます。

この記事では、他の方法を検討するためのポイントをご紹介します。

前提 (set_fact を利用する場合)

以下のような Playbook をベースに考えます。set_fact モジュールで、test_var 変数を定義し、その値を debug モジュールで表示するという簡単なものです。

- hosts: localhost
  gather_facts: no

  tasks:
    - name: set_fact
      set_fact:
        test_var: hogehoge

    - name: debug test
      debug:
        msg: "{{ test_var }}"


■ Play レベルの vars でよいのではないか

set_fact モジュールではなく、Play レベルvars で定義する方法です。

- hosts: localhost
  gather_facts: no

  vars:
    test_var: hogehoge
    
  tasks:
    - name: debug test
      debug:
        msg: "{{ test_var }}"

タスクの数も減ります。Playbook の実行ログは以下のとおりです。

$ ansible-playbook -i localhsot, test_vars.yml 

PLAY [localhost] **************************************************************************************************

TASK [debug test] *************************************************************************************************
ok: [localhost] => {
    "msg": "hogehoge"
}

PLAY RECAP ********************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

ただし、set_fact モジュールのように、ループとは併用できません。


■ Task レベルの vars でよいのではないか

set_fact モジュールではなく、Task レベルvars で定義する方法です。

- hosts: localhost
  gather_facts: no

  tasks:
    - name: debug test
      debug:
        msg: "{{ test_var }}"
      vars:
        test_var: hogehoge

実行ログは、前述のPlay レベルの vars で定義した場合と同じです。

ただし、スコープはこのタスクの範囲なので、他のタスクへの使いまわしはできません。逆にスコープを閉じ込めたい場合はメリットになるかも知れません。