Ansible:如何修改REST API返回的嵌套字典中的指定值?
问题描述
我在多个论坛(包括本论坛)搜索过,但都没找到合适的解决方案。在我的Ansible Playbook中,我使用uri模块调用REST API,并将结果注册为变量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确认这是一个字典类型。我需要将其中name为TLSv1.1的元素的enabled属性修改为false(注意JSON中false无需加引号)。我尝试创建新字典或修改原字典,但不知道如何仅更新该指定值。
我尝试了以下任务,但未能成功:
- 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'
注:由于公司限制,我无法安装jmespath用于JSON查询。
解决方案
可以通过Jinja2模板遍历嵌套列表修改指定元素,再重新组合成完整字典,全程无需额外工具。具体步骤如下:
- 生成修改后的协议版本列表
使用set_fact结合Jinja2循环,遍历原列表并修改目标元素的enabled值:
- set_fact: updated_protocols: >- {% set updated_list = [] %} {% for proto in result.json.protocol_versions %} {% if proto.name == 'TLSv1.1' %} {% do updated_list.append(proto | combine({'enabled': false})) %} {% else %} {% do updated_list.append(proto) %} {% endif %} {% endfor %} {{ updated_list }}
- 组合原字典与修改后的列表
用combine方法替换原字典中的protocol_versions字段,生成最终的更新后字典:
- set_fact: updated_result: "{{ result.json | combine({'protocol_versions': updated_protocols}, recursive=True) }}"
- 完整Playbook示例
整合后的完整Playbook如下:
- name: Fetch NSXT config and update TLSv1.1 setting hosts: localhost tasks: - name: Call NSXT API to get config 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 - name: Update TLSv1.1 enabled status to false set_fact: updated_protocols: >- {% set updated_list = [] %} {% for proto in result.json.protocol_versions %} {% if proto.name == 'TLSv1.1' %} {% do updated_list.append(proto | combine({'enabled': false})) %} {% else %} {% do updated_list.append(proto) %} {% endif %} {% endfor %} {{ updated_list }} - name: Generate updated config dictionary set_fact: updated_result: "{{ result.json | combine({'protocol_versions': updated_protocols}, recursive=True) }}" # 可选:打印结果验证修改是否生效 - name: Print updated config debug: var: updated_result
关键说明
- 使用Jinja2的
{% do %}语句向空列表添加元素,避免循环任务的冗余逻辑 combine方法配合recursive=True确保嵌套字典的字段正确替换- 全程仅依赖Ansible内置功能,无需安装额外工具
内容的提问来源于stack exchange,提问作者Kelvin Wong
相关产品推荐
相关产品推荐

