使用 Ansible 的 CLI 命令结果为 json

CLI Command result to json using Ansible

大家下午好,

我需要从 5 个交换机获取 BGP table 详细信息。 为此,我使用带有 Cisco 模块的 Ansible 在这 5 个交换机上发送 CLI 命令“show bgp l2vpn evpn vrf all”。

它运行良好,但我需要获取 JSON 才能过滤结果。

我尝试的第一个选项是使用 | json Ansible 中的选项:

---
- name: Playbook
  hosts: all
  gather_facts: false
  tasks:
  - name: run show bgp on remote devices
    cisco.nxos.nxos_command:
      commands: show bgp l2vpn evpn vrf all | json
    register: cli_result
  - local_action: 
      module: copy 
      content: "{{ cli_result | to_nice_json(indent=2) }}"
      dest: home/cli_result.json

此选项适用于一个交换机,但一旦我在 5 个交换机上启动它,我就好像内存不足或其他原因,我收到错误 错误!一名工人被发现处于死亡状态.

我不知道这个问题是否来自我正在使用的服务器,它不够强大,或者是否是其他原因。

此外,我注意到 | json 选项使剧本非常慢,当我在没有这个选项的情况下启动剧本时,它快了 5 倍。

所以我的问题是:有没有办法将 CLI 命令结果转换为 json,例如 Python?

当然,我尝试使用 python 模块 json 来转换它,但它正在将它转换成 12000 行的一大块,只有一个键和一个巨大的值。 而 | Ansible 中的 json 选项使许多不同的键变得非常清晰。

这是 CLI 命令的结果:

BGP routing table information for VRF default, address family L2VPN EVPN
BGP table version is xxxxx, Local Router ID is xx.xx.xx.xx
Status: s-suppressed, x-deleted, S-stale, d-dampened, h-history, *-valid, >-best
Path type: i-internal, e-external, c-confed, l-local, a-aggregate, r-redist, I-injected
Origin codes: i - IGP, e - EGP, ? - incomplete, | - multipath, & - backup, 2 - best2

   Network            Next Hop            Metric     LocPrf     Weight Path
Route Distinguisher: xxxxx:xxxxx
* i[x]:[0]:[0]:[xx]:[xxxx.xxxx.xxxx]:[0]:[0.0.0.0]/xxx
                      xx.xx.xx.xx                     000          0 xxxxx xxxxx i
*>i                   xx.xx.xx.xx                     000          0 xxxxx xxxxx i
* i[x]:[0]:[0]:[xx]:[xxxx.xxxx.xxxx]:[0]:[0.0.0.0]/xxx
                      xx.xx.xx.xx                     000          0 xxxxx xxxxx i
*>i                   xx.xx.xx.xx                     000          0 xxxxx xxxxx i
.......

这是 | 的结果json Ansible 选项:

{
  "changed": false,
  "failed": false,
  "stdout": [
    {
      "TABLE_vrf": {
        "ROW_vrf": {
          "TABLE_afi": {
            "ROW_afi": {
              "TABLE_safi": {
                "ROW_safi": {
                  "TABLE_rd": {
                    "ROW_rd": [
                      {
                        "TABLE_prefix": {
                          "ROW_prefix": [
                            {
                              "TABLE_path": {
                                "ROW_path": [
                                  {
                                    "aspath": "xxxxx xxxxx",
                                    "best": "none",
                                    "bestcode": null,
                                    "ipnexthop": "0.0.0.0",
                                    "localpref": "000",
                                    "origin": "i",
                                    "pathnr": "0",
                                    "status": "valid",
                                    "statuscode": "*",
                                    "type": "internal",
                                    "typecode": "i",
                                    "weight": "0"
                                  },
                                  {
                                    "aspath": "xxxxx xxxxx",
                                    "best": "bestpath",
                                    "bestcode": ">",
                                    "ipnexthop": "0.0.0.0",
                                    "localpref": "000",
                                    "origin": "i",
                                    "pathnr": "1",
                                    "status": "valid",
                                    "statuscode": "*",
                                    "type": "internal",
                                    "typecode": "i",
                                    "weight": "0"
                                  }
                                ]
                              },
                              "nonipprefix": "[x]:[0]:[0]:[xx]:[xxxx.xxxx.xxxx]:[0]:[0.0.0.0]/xxx"
                            },

这是我用 Python 转换的 CLI 命令的结果:

{
  "changed": false,
  "failed": false,
  "stdout": [containing the whole block of cli command result with ',' after each line]
}

非常感谢您的帮助,

问:“有没有办法将CLI命令结果转换成JSON?”

答:在你的情况下,最好的选择可能是 ansible.netcommon.cli_parse


问:“正在为一个开关工作,但一旦我在 5 个开关上启动它...”

答:你运行任务local_action同时进行所有切换。 运行 它只写一次并写入所有数据,例如,在字典中。鉴于清单和下面的剧本进行测试

shell> cat hosts
sw1
sw2
sw3
shell> cat playbook.yml
- name: Playbook
  hosts: all
  gather_facts: false
  tasks:
  - set_fact:
      cli_result:
        stdout:
          - TABLE_vrf:
              ROW_vrf: to be continued
  - copy:
      content: "{{ _dict|to_nice_yaml(indent=2) }}"
      dest: cli_result.json
    delegate_to: localhost
    run_once: true
    vars:
      _keys: "{{ ansible_play_hosts }}"
      _vals: "{{ ansible_play_hosts|
                 map('extract', hostvars, ['cli_result', 'stdout'])|
                 list }}"
      _dict: "{{ dict(_keys|zip(_vals)) }}"

剧本创建文件cli_result.json

sw1:
- TABLE_vrf:
    ROW_vrf: to be continued
sw2:
- TABLE_vrf:
    ROW_vrf: to be continued
sw3:
- TABLE_vrf:
    ROW_vrf: to be continued