使用DHCP IP部署VM之后,我想获取IP并将其附加到guest虚拟机字典中。
对于第一个VM(testvm2),代码将按预期执行,并更新testvm2 VM的tempip变量。
但是对于第二个VM(testvm1),它将使用第二个VM(testvm1)的IP更新第一个VM(testvm2)的tempip变量,并使用代码更新第二个VM(testvm1)的tempip变量'{{tempip_reg.stdout_lines}}'
有人可以向我解释为什么会这样吗? 我会很感激的。
我复制了所有相关代码,并在下面输出:
宾客字典:
---
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
生成第一个VM:
"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
}
}
结果第二个虚拟机:
"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
}
}
答案 0 :(得分:0)
TL; DR
使用Ansible代码,您正在尝试实现Ansible已经为您完成的工作。
您的尝试与内置功能叠加在一起,您会得到不确定的结果。
说明:
您的代码的主要问题是用with_dict: "{{ guests }}"
声明的完全不必要的循环,这导致该文件包含4次。
它运行4次是因为您更改了guests
字典,该字典在包含的任务文件内循环。
实际上,您得到的结果看起来像是不确定的结果。
第二个问题很简单:您始终用字符串tempip
替换{{ tempip_reg.stdout_lines }}
的值。
现在,由于在动态更改的字典上进行了不必要的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
和provision-tasks.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
}
}
最后,在上述播放中,您在错误的上下文中使用了group_vars
和roles/tasks
目录。我保留了完整的路径,它们将适用于上面的代码,但是基本上,您永远不要以这种方式使用它们,因为它们再次在Ansible中具有特殊的意义和处理。