Dictionary 可变嵌套dict变量
在使用DHCP IP部署VM之后,我想获取IP并将其附加到来宾字典中 对于第一个VM(testvm2),代码按预期执行,并更新testvm2 VM的tempip变量 但是对于第二个VM(testvm1),它用第二个VM(testvm1)的IP更新第一个VM(testvm2)的tempip变量,并用变量{{tempip_reg.stdout_lines}的代码更新第二个VM(testvm1)的tempip变量 有人能解释一下为什么会发生这种情况吗? 我将非常感谢你的帮助 我复制了以下所有相关代码和输出: 来宾词典: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变量 有人能解释一下为什么会发生这种情况吗? 我将非常感谢你的帮助 我复制了以下所有相关代码和
---
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
- 现在,由于动态更改字典上不必要的
循环,并且因为Jinja2使用惰性变量求值,所以先前迭代中的字符串被解释为模板,并在后续迭代中使用不正确的值求值 最后一次迭代使字符串with_dict
保持不变{{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次。谢谢你的投入,我从中学到了很多。