Dictionary 可变嵌套dict变量

Dictionary 可变嵌套dict变量,dictionary,ansible,Dictionary,Ansible,在使用DHCP IP部署VM之后,我想获取IP并将其附加到来宾字典中 对于第一个VM(testvm2),代码按预期执行,并更新testvm2 VM的tempip变量 但是对于第二个VM(testvm1),它用第二个VM(testvm1)的IP更新第一个VM(testvm2)的tempip变量,并用变量{{tempip_reg.stdout_lines}的代码更新第二个VM(testvm1)的tempip变量 有人能解释一下为什么会发生这种情况吗? 我将非常感谢你的帮助 我复制了以下所有相关代码和

在使用DHCP IP部署VM之后,我想获取IP并将其附加到来宾字典中

对于第一个VM(testvm2),代码按预期执行,并更新testvm2 VM的tempip变量

但是对于第二个VM(testvm1),它用第二个VM(testvm1)的IP更新第一个VM(testvm2)的tempip变量,并用变量{{tempip_reg.stdout_lines}的代码更新第二个VM(testvm1)的tempip变量

有人能解释一下为什么会发生这种情况吗? 我将非常感谢你的帮助

我复制了以下所有相关代码和输出:

来宾词典:

---
guests:
  testvm1:
    mem: 512
    cpus: 1
    clone: template-centos
    vmid: 102
    tempip:

  testvm2:
    mem: 1536
    cpus: 2
    clone: template-centos
    vmid: 102
    tempip:
启动任务的Ansible Playbook:

---
- name: Provision VMs
  hosts: infra
  become: true
  vars_files:
    - group_vars/vms.yml
    - group_vars/vars.yml
  tasks:
    - include_tasks: roles/tasks/provision-tasks.yml
      with_dict: "{{ guests }}"
负责的任务:

- name: Run proxmox-get-ip-linux.sh script to register DHCP IP of VM
  script: proxmox-get-ip-linux.sh "{{ item.key }}"
  register: tempip_reg

- name: temporary IP of VM "{{ item.key }}"
  debug:
    var: tempip_reg

- name: current host in item.key
  set_fact:
    current_host: "{{ item.key }}"

- name: current_host variable set to
  debug:
    var: current_host

- name: append item.value.tempip with the DHCP IP of the VM registered in 
 last task
  set_fact:
    guests: "{{ guests|combine({ current_host: {'tempip': '{{ tempip_reg.stdout_lines }}' }}, recursive=True) }}"

- name: temporary IP of "{{ item.key }}"
  debug: var=guests
结果第一个虚拟机:

"tempip_reg": {
    "stdout": "192.168.1.21\r\n",
    "stdout_lines": [
        "192.168.1.21"
    }

"current_host": "testvm2"

"guests": {
    "testvm1": {
        "clone": "template-centos",
        "cpus": 1,
        "ip": "192.168.1.60",
        "mem": 512,
        "tempip": null,
        "vmid": 102
    },
    "testvm2": {
        "clone": "template-centos",
        "cpus": 2,
        "ip": "192.168.1.61",
        "mem": 1536,
        "tempip": [
            "192.168.1.21"
        ],
        "vmid": 102
    }
}
结果2:

"tempip_reg": {
    "stdout": "192.168.1.22\r\n",
    "stdout_lines": [
        "192.168.1.22"
    }

    "current_host": "testvm1"

"guests": {
    "testvm1": {
        "clone": "template-centos",
        "cpus": 1,
        "ip": "192.168.1.60",
        "mem": 512,
        "tempip": "{{ tempip_reg.stdout_lines }}",
        "vmid": 102
    },
    "testvm2": {
        "clone": "template-centos",
        "cpus": 2,
        "ip": "192.168.1.61",
        "mem": 1536,
        "tempip": [
            "192.168.1.22"
        ],
        "vmid": 102
    }
}
TL;DR

使用Ansible代码,您正试图实现Ansible已经为您做的事情

您的尝试与内置功能叠加,结果看起来不确定


说明:

  • 代码的主要问题是使用
    和{{{guests}}{/code>声明了一个完全不必要的循环,这导致包含文件4次

    它运行了4次,因为您更改了
    guests
    字典,它在包含的任务文件中循环该字典

    实际上,你得到的结果看起来像是一个不确定的结果

  • 第二个问题很简单:总是用字符串
    {{tempip\u reg.stdout\u lines}
    替换
    tempip
    的值

  • 现在,由于动态更改字典上不必要的
    with_dict
    循环,并且因为Jinja2使用惰性变量求值,所以先前迭代中的字符串被解释为模板,并在后续迭代中使用不正确的值求值

    最后一次迭代使字符串
    {{tempip_reg.stdout_lines}}
    保持不变

  • 您还可以定义并打印两个不同的事实


你应该做什么:

  • 您根本不应该声明任意迭代。Ansible为所有主机本身实现一个循环。也就是说,如果您声明了一个任务:

    - include_tasks: roles/tasks/provision-tasks.yml
    
    该文件将包含在
    infra
    组中的每个主机中(在您的示例中两次)

  • 您似乎希望拥有数据结构的一个副本,其中包含每个VM的更新值

    同时,创建一个事实,它是为每个主机分别维护的一个单独的数据对象

    因此,您应该引用并修改(
    combine
    )一个事实-您可以在
    localhost
    上这样做


您的代码结构应如下所示:

---
- name: Provision VMs
  hosts: infra
  become: true
  vars_files:
    - group_vars/vms.yml
    - group_vars/vars.yml
  tasks:
    - include_tasks: roles/tasks/provision-tasks.yml
    - debug:
        var: hostvars['localhost'].guests
供应任务.yml

- set_fact:
    guests: "{{ guests|combine({ current_host: {'tempip': tempip_reg.stdout_lines }}, recursive=True) }}"
  delegate_to: localhost
这将得到以下结果:

"hostvars['localhost'].guests": {
    "testvm1": {
        "clone": "template-centos",
        "cpus": 1,
        "ip": "192.168.1.60",
        "mem": 512,
        "tempip": [
            "192.168.1.21"
        ],
        "vmid": 102
    },
    "testvm2": {
        "clone": "template-centos",
        "cpus": 2,
        "ip": "192.168.1.61",
        "mem": 1536,
        "tempip": [
            "192.168.1.22"
        ],
        "vmid": 102
    }
}


最后,在上面的剧本中,您在错误的上下文中使用了
组变量
角色/任务
目录。我保留了完整的路径,它们将适用于上述代码,但基本上您不应该以这种方式使用它们,因为它们在Ansible中有特殊的含义和处理方式。

您是否尝试过替换
{tempip_reg.stdout_line}
使用
tempip_reg.stdout_行
因为它们在行首和行尾都是花括号。这确实是解决方案,谢谢。您为任务提供的set_事实修复了问题,我使用的变量错误。如果我在启动任务时从剧本中删除:“{{guests}}”,这将在两个VM之间共享任务,而不是每个VM运行它们。我不认为它运行了4次。谢谢你的投入,我从中学到了很多。