You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ansible中使用循环替换字典值失败,如何解决?

问题:Ansible循环替换字典中vm_name字段失败

我编写了一个Ansible Playbook,用于从Nutanix Prism Central拉取虚拟机列表,捕获vm_name与UUID后,将VM短名称替换为生成的FQDN。但在循环替换字典变量中的vm_name时遇到错误:

"The task includes an option with an undefined variable. The error was: str object has no element AnsibleUndefined(hint=None, obj=missing, name='loop')"

最小可复现代码

---
- name: Test of value replacement
  hosts: all
  gather_facts: False
  vars:
    clone_vm:
      - {  uuid: "ac1fd960-e19a-48f3-935b-442901ef5fee", vm_name: "server1" }
      - {  uuid: "f44880f6-49aa-4ba3-8cba-403ff06f1c5e", vm_name: "server2" }
    fqdns:
         - "mymachine@mycompany.com"
         - "myothermachine@mycompany.com"

  tasks:
    - name: Show variable
      debug:
        msg:
        - "{{ clone_vm }}"
        - "{{ fqdns }}"

    - name: Replace vm_name with FQDN
      set_fact:
        clone_vm: "{{ clone_vm | map('combine', [{'vm_name': item[loop.index0]}]) }}"
      loop: "{{ fqdns }}"
      loop_control:
        loop_var: item

    - debug:
        msg: "{{ clone_vm }}"

若将[{'vm_name': item[loop.index0]}]修改为[{'vm_name': item.[loop.index0]}],会触发另一个错误:

template error while templating string: expected name or number. String: {{ clone_vm | map('combine', [{'vm_name': item.[loop.index0]}]) }}. expected name or number

原数据与期望输出

原数据

- uuid: ac1fd960-e19a-48f3-935b-442901ef5fee
  vm_name: server1
- uuid: f44880f6-49aa-4ba3-8cba-403ff06f1c5e
  vm_name: server2

期望输出

- uuid: ac1fd960-e19a-48f3-935b-442901ef5fee
  vm_name: myserver.mycompany.com
- uuid: f44880f6-49aa-4ba3-8cba-403ff06f1c5e
  vm_name: myotherserver.mycompany.com

解决方案

错误根源在于:过滤器上下文无法访问task的loop变量,且原写法会在每次循环中重复修改整个clone_vm列表,逻辑错误。

可以通过一次性配对两个列表并合并字典的方式解决,无需使用loop循环:

方法1:使用Jinja2模板生成更新后的列表

- name: Replace vm_name with FQDN
  set_fact:
    clone_vm: >-
      {% set updated_vms = [] %}
      {% for vm, fqdn in clone_vm | zip(fqdns) %}
        {% set _ = updated_vms.append(vm | combine({'vm_name': fqdn})) %}
      {% endfor %}
      {{ updated_vms }}

方法2:使用zip+map过滤器组合

- name: Replace vm_name with FQDN
  set_fact:
    clone_vm: "{{ clone_vm | zip(fqdns) | map('lambda x: x[0] | combine({'vm_name': x[1]})) | list }}"

这两种方法都会将clone_vm中的每个VM字典与fqdns中对应位置的FQDN配对,替换vm_name字段后生成新列表,完全符合期望输出。

内容的提问来源于stack exchange,提问作者Andrew Madsen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 01:42:46