首页 > 解决方案 > 在 Ansible 中检索、操作和发回 JSON

问题描述

我们必须为交换机设置和取消设置 VLAN 配置。幸运的是,Unify Controller 提供了一个 API,它通常与 Ansible 一起使用。

但是,使用 API 更改单个元素是不可能的,Ansible 必须获取当前配置,找到并更改所需的元素并发回配置。(我推动了所需的配置更改。这导致交换机除了我的配置更改之外什么都没有,我觉得像 Facebook 的人......)

---
- hosts: adm01.local
  gather_facts: false
  tasks:

  - name: Use vars from Vault
    include_vars: unifi_info.yaml

  - name: Get Cookie from Unifi
    uri:
      url: https://{{ url }}/api/login
      method: POST
      body_format: json
      body: {"username":"{{ username }}","password":"{{ password }}"}
      validate_certs: false
    register: login

  - name: Print returned data to ensure it worked
    debug:
      msg: "{{ login }}"

  - name: Get current config
    uri:
      url: https://{{ url }}/api/s/default/stat/device/
      method: GET
      body_format: json
      headers:
        Cookie: "{{ login.cookies_string }}"
      validate_certs: false
    register: switchConf

  - name: Print SwitchConf
    debug:
      msg: "{{ switchConf }}"

  - name: Set port 2 to CLIENTVLAN
    uri:
      url: https://{{ url }}/api/s/default/rest/device/60acc79964542d80774123b5/
      method: PUT
      body_format: json
      # DISABLE VLAN: "60aca5ee64542d807741239d"
      # CLIENTVLAN: ""60accb9b64542d80774123d1"
      #body: {"port_overrides": [{"port_idx": 2, "portconf_id":"60accb9b64542d80774123d1"}]}
      headers:
        Cookie: "{{ login.cookies_string }}"
      validate_certs: false
    register: portConf

  - name: Print portConf
    debug:
      msg: "{{ portConf }}"

SwitchConf 打印(仅相关部分):

    "msg": {
        "access_control_allow_credentials": "true",
        "access_control_expose_headers": "Access-Control-Allow-Origin,Access-Control-Allow-Credentials",
        "changed": false,
        "connection": "close",
        "content_type": "application/json;charset=UTF-8",
        "cookies": {},
        "cookies_string": "",
        "date": "Wed, 20 Oct 2021 18:22:24 GMT",
        "elapsed": 0,
        "failed": false,
        "json": {
            "data": [
                {
                    (...)
                    "port_overrides": [
                        {
                            "port_idx": 1,
                            "portconf_id": "A"
                        },
                        {
                            "port_idx": 2,
                            "portconf_id": "B"
                        },
                        {
                            "port_idx": 3,
                            "portconf_id": "B"
                        },
                        {
                            "port_idx": 5,
                            "portconf_id": "B"
                        },
                        {
                            "port_idx": 6,
                            "portconf_id": "B"
                        },
                        {
                            "port_idx": 7,
                            "portconf_id": "B"
                        },
                        (...)
                    ],
                    (...)
                }
            ]
        },
        "msg": "OK (unknown bytes)",
        "redirected": false,
        "status": 200,
        "transfer_encoding": "chunked",
        "url": "https://adm01.local:8443/api/s/default/stat/device/",
        "vary": "accept-encoding,origin,accept-encoding",
        "x_frame_options": "DENY"
    }
}

所以,问题是:如何使用 Ansible 获取 JSON 数据报 portConf->data->port_overrides 并将“portconf_id”更改为“X”,“port_idx”==2,以便使用 post_overrides 对其进行 POST背部?

标签: jsonansible

解决方案


YAML 中的字典是不可变的。你必须创建一个新的来改变任何东西。鉴于简化数据

    portConf:
      status: 200
      json:
        data:
          - port_overrides:
              - port_idx: 1
                portconf_id: A
              - port_idx: 2
                portconf_id: B
              - port_idx: 3
                portconf_id: C

以及所需的更改

    diff:
      port_idx: 2
      portconf_id: X

下面的任务对json.data进行了更改

    - set_fact:
        _json: "{{ {'data': [{'port_overrides': _port_change}]} }}"
      vars:
        _port_remove: "{{ portConf.json.data.0.port_overrides|
                          rejectattr('port_idx', 'eq', diff.port_idx)|
                          list }}"
        _port_change: "{{ (_port_remove + [diff])|sort(attribute='port_idx') }}"

  _json:
    data:
    - port_overrides:
      - port_idx: 1
        portconf_id: A
      - port_idx: 2
        portconf_id: X
      - port_idx: 3
        portconf_id: C

下一个任务结合了这些变化

    - set_fact:
        portConf: "{{ portConf|combine({'json': _json}) }}"

  portConf:
    json:
      data:
      - port_overrides:
        - port_idx: 1
          portconf_id: A
        - port_idx: 2
          portconf_id: X
        - port_idx: 3
          portconf_id: C
    status: 200

推荐阅读