如何解决Ansible循环迭代覆盖字典列表值的问题
Ansible循环更新字典列表时值被覆盖的问题解决
问题场景
初始字典列表:
"ne_hosts": [ { "instance_class": "docker_host", "ip": "10.11.12.15" }, { "instance_class": "vm_host", "ip": "10.11.12.13" } ]
期望为每个字典添加ip_present键(IP在配置文件中存在则为0,不存在则为1),得到:
"ne_hosts_updated": [ { "instance_class": "docker_host", "ip": "10.11.12.15", "ip_present": 1 }, { "instance_class": "vm_host", "ip": "10.11.12.13", "ip_present": 0 } ]
执行以下任务后,所有字典的ip_present值都等于最后一次检查的IP结果:
- name: Check if host IP is present in a config file ansible.builtin.command: grep -q "{{ target_config_file_location }}" -e "{{ item.ip }}" loop: "{{ ne_hosts }}" ignore_errors: true register: ip_present - name: Update the IPs list set_fact: ne_hosts_updated: "{{ ne_hosts | default([]) | map('combine', {'ip_present': item.rc }) | list }}" loop: "{{ ip_present.results }}"
问题原因
第二个任务的set_fact每次循环都会对整个ne_hosts列表执行map('combine')操作,把列表里的所有元素都和当前循环的item.rc组合。循环结束后,ne_hosts_updated会保留最后一次循环的处理结果,也就是所有元素的ip_present都等于最后一个IP的检查结果。
正确解决方案
方法1:用zip打包对应元素
通过zip将ne_hosts和ip_present.results按索引一一配对,逐个组合生成新列表:
- name: Update the IPs list set_fact: ne_hosts_updated: "{{ ne_hosts_updated | default([]) + [ item.0 | combine({'ip_present': item.1.rc}) ] }}" loop: "{{ ne_hosts | zip(ip_present.results) | list }}"
方法2:利用循环索引匹配
开启扩展循环控制,通过ansible_loop.index0获取当前循环的索引,对应取ne_hosts里的元素:
- name: Update the IPs list set_fact: ne_hosts_updated: "{{ ne_hosts_updated | default([]) + [ ne_hosts[ansible_loop.index0] | combine({'ip_present': item.rc}) ] }}" loop: "{{ ip_present.results }}" loop_control: extended: yes
两种方法都能保证每个字典的ip_present值对应自身IP的检查结果,不会被后续循环覆盖。
内容的提问来源于stack exchange,提问作者AbreQueVoy
相关产品推荐
相关产品推荐

