Ansible:如何通过REST API调用更新或更改嵌套字典中的值?

huangapple go评论98阅读模式
英文:

Ansible: How to update or change a value in a nested dictionary from a REST API call?

问题

在这个播放书中,我正在使用uri模块进行调用,注册一个名为result的变量。

result.json看起来像这样:

{
    "global_api_concurrency_limit": 199,
    "client_api_rate_limit": 100,
    "client_api_concurrency_limit": 40,
    "connection_timeout": 30,
    "redirect_host": "",
    "protocol_versions": [
        {"enabled": true, "name": "TLSv1.1"},
        {"enabled": true, "name": "TLSv1.2"}
    ]
}

我通过result.json | type_debug检查它,并显示它是一个字典。

我想要将属性更新为"enabled": false,其中"name": "TLSv1.1"

请注意,JSON中的false不用引号括起来。所以我的想法是要么创建一个新的字典,要么更新同一个字典。但我不知道如何只更新那个值。

我尝试了下面的任务,但显然没有起作用。

  - name: 调用NSXT
    vars:
      api: "/api/v1/cluster/api-service"
    ansible.builtin.uri:
      url: "https://server01{{ api }}"
      user: user1
      password: pwd1
      method: GET
      force_basic_auth: true
      validate_certs: false
      headers:
        Content-Type: application/json
    register: result

  - set_fact:
      newdic: "{{ (newdic | d([])) | combine(new_item, recursive=True) }}"
    with_dict: "{{ result.json }}"
    vars:
      new_item: {'enabled': false}
    when: item.protocol_versions.name == 'TLSv1.1'

有没有什么建议来改进这个?(注意:我不想安装jmespath进行JSON查询,因为公司有限制。)

我无法弄清楚如何只更新嵌套字典中的一个值?

英文:

I had search in a few forums including this one, but none of them seems to be able to provide the solution for me. In the playbook, I am doing a call via uri module that registers a variable: result.

result.json looks like this

{
"global_api_concurrency_limit": 199,
"client_api_rate_limit": 100,
"client_api_concurrency_limit": 40,
"connection_timeout": 30,
"redirect_host": "",
"protocol_versions": [
{"enabled": true, "name": "TLSv1.1"},
{"enabled": true, "name": "TLSv1.2"}
]
}

I checked via result.json | type_debug and says its a dictionary.

I want to update property to "enabled": false where "name": "TLSv1.1".

Noting that false is not quoted in the JSON. So my idea is to either create a new dict or update the same dict. But I am stuck how I can update only that value.

I attempted the below tasks, but it obviously didn't work.

  - name: Call NSXT
    vars:
      api: "/api/v1/cluster/api-service"
    ansible.builtin.uri:
      url: "https://server01{{ api }}"
      user: user1
      password: pwd1
      method: GET
      force_basic_auth: true
      validate_certs: false
      headers:
        Content-Type: application/json
    register: result

  - set_fact:
      newdic: "{{ (newdic | d([])) | combine(new_item, recursive=True) }}"
    with_dict: "{{ result.json }}"
    vars:
      new_item: {'enabled': false}
    when: item.protocol_versions.name == 'TLSv1.1'

Any advise how to improve this? (Note: I don't want to install jmespath for JSON queries, because of company restrictions)

I couldn't figure out how I can only update one value with that nested dictionary?

答案1

得分: 1

根据您的描述,我想知道是否您可以使用 update_fact 模块 - 更新当前设置的事实?它用于更新变量,其中文档中的一个 示例 似乎与您的情况类似。

根据您提供的示例数据,一个最小的示例 playbook

---
- hosts: localhost
  become: false
  gather_facts: false

  tasks:

  - include_vars:
      file: result.json
      name: result

  - ansible.utils.update_fact:
      updates:
        - path: result.protocol_versions[0]
          value: {"enabled": false, "name": "TLSv1.1"}
    register: updated

  - debug:
      var: updated

将产生以下输出

TASK [debug] *************************
ok: [localhost] =>
  updated:
    changed: true
    failed: false
    result:
      client_api_concurrency_limit: 40
      client_api_rate_limit: 100
      connection_timeout: 30
      global_api_concurrency_limit: 199
      protocol_versions:
      - enabled: false
        name: TLSv1.1
      - enabled: true
        name: TLSv1.2
      redirect_host: ''

如果不清楚 result.protocol_versions 是否包含正确的版本,或者顺序不清楚,也可以定义配置的期望状态。

  - ansible.utils.update_fact:
      updates:
        - path: result.protocol_versions
          value: [{"enabled": false, "name": "TLSv1.1"}, {"enabled": true, "name": "TLSv1.2"}]
    register: updated

请注意,即使使用 update_fact 模块 - 更新当前设置的事实

变量不会在原地修改,而是由模块返回。

这是预期的行为

英文:

According your description I wonder if you could use the update_fact module – Update currently set facts? It is intended for updating variables and one of the documented Examples seems to be similar to yours.

Based on your provided sample data, a minimal example playbook

---
- hosts: localhost
  become: false
  gather_facts: false

  tasks:

  - include_vars:
      file: result.json
      name: result

  - ansible.utils.update_fact:
      updates:
        - path: result.protocol_versions[0]
          value: {"enabled": false, "name": "TLSv1.1"}
    register: updated

  - debug:
      var: updated

will result into an output of

TASK [debug] *************************
ok: [localhost] =>
  updated:
    changed: true
    failed: false
    result:
      client_api_concurrency_limit: 40
      client_api_rate_limit: 100
      connection_timeout: 30
      global_api_concurrency_limit: 199
      protocol_versions:
      - enabled: false
        name: TLSv1.1
      - enabled: true
        name: TLSv1.2
      redirect_host: ''

If it is not clear if the result.protocol_versions will contain the correct versions, of if the order is not clear, it is also possible to define the desired state of the configuration.

  - ansible.utils.update_fact:
      updates:
        - path: result.protocol_versions
          value: [{"enabled": false, "name": "TLSv1.1"}, {"enabled": true, "name": "TLSv1.2"}]
    register: updated

Please take note that even if using update_fact module – Update currently set facts

> Variables are not modified in place, instead they are returned by the module.

and that is the expected behavior.

答案2

得分: 0

  • ansible.utils.update_fact:
    updates:
    - path: "result.json.protocol_versions[{{item}}].enabled"
    value: false
    loop: "{{ range(result.json.protocol_versions|length) }}"
    when: result.json.protocol_versions[{{item}}].name == "TLSv1.1"
    register: updated
英文:

Looks like I found the answer, this will update just the row with name=TLSv1.1

  - ansible.utils.update_fact:
      updates:
        - path: "result.json.protocol_versions[{{item}}].enabled"
          value: false
    loop: "{{ range(result.json.protocol_versions|length) }}"
    when: result.json.protocol_versions[{{item}}].name == "TLSv1.1"
    register: updated

huangapple
  • 本文由 发表于 2023年7月20日 17:21:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76728408.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定