如何将vmware_guest部署的VM变量传递给Ansible角色以完成配置
Ansible部署VM后变量传递失败问题解决
问题概述
使用vmware_guest模块成功部署新VM,通过add_host将VM加入清单后,执行后续角色配置时提示vm_info未定义。VM部署流程正常,但后续配置playbook报错。
原Playbook代码
--- - name: Deploy the VM hosts: localhost gather_facts: no tasks: - name: "Create VM from template" vmware_guest: validate_certs: false username: "{{ vcenter_username }}" password: "{{ vcenter_password }}" datacenter: "{{ vcenter_datacenter }}" cluster: "{{ vm_cluster }}" template: "{{ vm_template }}" name: "{{ vm_name }}" folder: "{{ vm_folder }}" hardware: num_cpus: "{{ vm_hw_cpu_n }}" memory_mb: "{{ vm_hw_ram_mb }}" disk: - size_gb: "{{ vm_disk_gb }}" type: thin datastore: "{{ vm_datastore_cluster }}" networks: - name: "{{ vm_net_name }}" type: static device_type: vmxnet3 ip: 172.16.100.123 netmask: 255.255.255.0 gateway: 172.16.100.1 connected: true start_connected: true customization: hostname: "{{ vm_name }}.domain.invalid" domain: domain.invalid dns_servers: - 172.16.100.10 - 172.16.100.11 dns_suffix: - domain.invalid state: present wait_for_ip_address: true register: vm_info - name: Add host to inventory ansible.builtin.add_host: name: "{{ vm_info.instance.ipv4 }}" groups: vmware_vms - name: Run Additional Configurations hosts: vmware_vms roles: - role: base vars: var_vm_name: "{{ vm_name }}" var_vm_ip: "{{ vm_info.instance.ipv4 }}" var_vm_domain: "{{ vm_info.customization.domain }}" var_vm_fqdn: "{{ vm_info.customization.hostname }}" var_vm_dnsservers: "{{ vm_info.customization.dns_servers }}"
错误信息
"msg": "AnsibleUndefinedVariable: 127.0.0.1 localhost 127.0.1.1 {{ var_vm_name }} {{ var_vm_ip }} {{ var_vm_fqdn }} {{ var_vm_name }} # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters : {{ vm_info.instance.ipv4 }}: 'vm_info' is undefined. 'vm_info' is undefined. {{ vm_info.instance.ipv4 }}: 'vm_info' is undefined. 'vm_info' is undefined. 127.0.0.1 localhost 127.0.1.1 {{ var_vm_name }} {{ var_vm_ip }} {{ var_vm_fqdn }} {{ var_vm_name }} # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters : {{ vm_info.instance.ipv4 }}: 'vm_info' is undefined. 'vm_info' is undefined. {{ vm_info.instance.ipv4 }}: 'vm_info' is undefined. 'vm_info' is undefined", "exception": "Traceback (most recent call last): File \"/usr/lib/python3.9/site-packages/ansible/template/__init__.py\", line 1004, in do_template res = myenv.concat(rf) File \"/usr/lib/python3.9/site-packages/ansible/template/native_helpers.py\", line 83, in ansible_concat return ''.join([to_text(v) for v in nodes]) File \"/usr/lib/python3.9/site-packages/ansible/template/native_helpers.py\", line 83, in <listcomp> return ''.join([to_text(v) for v in nodes]) File \"<template>\", line 12, in root File \"/usr/lib/python3.9/site-packages/ansible/template/__init__.py\", line 295, in wrapper ret = func(*args, **kwargs) File \"/usr/lib/python3.9/site-packages/ansible/template/__init__.py\", line 547, in _ansible_finalize return thing if _fail_on_undefined(thing) is not None else '' File \"/usr/lib/python3.9/site-packages/ansible/template/__init__.py\", line 519, in _fail_on_undefined elif is_sequence(data): File \"/usr/lib/python3.9/site-packages/ansible/module_utils/common/collections.py\", line 94, in is_sequence if not include_strings and is_string(seq): File \"/usr/lib/python3.9/site-packages/jinja2/runtime.py\", line 852, in _fail_with_undefined_error raise self._undefined_exception(self._undefined_message) ansible.errors.AnsibleUndefinedVariable: 127.0.0.1 localhost 127.0.1.1 {{ var_vm_name }} {{ var_vm_ip }} {{ var_vm_fqdn }} {{ var_vm_name }} # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters : {{ vm_info.instance.ipv4 }}: 'vm_info' is undefined. 'vm_info' is undefined. {{ vm_info.instance.ipv4 }}: 'vm_info' is undefined. 'vm_info' is undefined During handling of the above exception, another exception occurred: Traceback (most recent call last): File \"/usr/lib/python3.9/site-packages/ansible/plugins/action/template.py\", line 152, in run resultant = templar.do_template(template_data, preserve_trailing_newlines=True, escape_backslashes=False, overrides=overrides) File \"/usr/lib/python3.9/site-packages/ansible/template/__init__.py\", line 1038, in do_template raise AnsibleUndefinedVariable(e, orig_exc=e) ansible.errors.AnsibleUndefinedVariable: 127.0.0.1 localhost 127.0.1.1 {{ var_vm_name }} {{ var_vm_ip }} {{ var_vm_fqdn }} {{ var_vm_name }} # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters : {{ vm_info.instance.ipv4 }}: 'vm_info' is undefined. 'vm_info' is undefined. {{ vm_info.instance.ipv4 }}: 'vm_info' is undefined. 'vm_info' is undefined. 127.0.0.1 localhost 127.0.1.1 {{ var_vm_name }} {{ var_vm_ip }} {{ var_vm_fqdn }} {{ var_vm_name }} # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters : {{ vm_info.instance.ipv4 }}: 'vm_info' is undefined. 'vm_info' is undefined. {{ vm_info.instance.ipv4 }}: 'vm_info' is undefined. 'vm_info' is undefined ", "_ansible_no_log": null, "changed": false
错误原因
Ansible的不同Play之间变量是隔离的:vm_info是在第一个针对localhost的Play中注册的变量,仅存在于该Play的执行上下文;第二个针对vmware_vms组的Play无法直接访问这个变量,导致报错。同时,base角色的模板中可能直接引用了vm_info,而非传递过来的变量。
解决方案
方法一:通过add_host传递主机变量(推荐)
修改add_host任务,将需要的变量直接附加到新添加的主机上,作为该主机的专属变量:
- name: Add host to inventory ansible.builtin.add_host: name: "{{ vm_info.instance.ipv4 }}" groups: vmware_vms # 直接传递需要的变量到新主机 var_vm_name: "{{ vm_name }}" var_vm_ip: "{{ vm_info.instance.ipv4 }}" var_vm_domain: "{{ vm_info.customization.domain }}" var_vm_fqdn: "{{ vm_info.customization.hostname }}" var_vm_dnsservers: "{{ vm_info.customization.dns_servers }}"
然后修改第二个Play,直接使用主机变量,无需再引用vm_info:
- name: Run Additional Configurations hosts: vmware_vms roles: - role: base # 这里无需重复定义vars,主机变量会自动传递到角色中
同时检查base角色的模板,确保模板中使用{{ var_vm_ip }}这类传递过来的变量,而非直接引用{{ vm_info.instance.ipv4 }}。
方法二:全局持久化变量(不推荐,仅特殊场景使用)
如果需要跨Play共享变量,可使用set_fact结合persist=True将变量保存到本地facts缓存:
- name: Save VM info as global fact ansible.builtin.set_fact: global_vm_info: "{{ vm_info }}" persist: true
然后在第二个Play中引用全局变量:
- name: Run Additional Configurations hosts: vmware_vms roles: - role: base vars: var_vm_name: "{{ vm_name }}" var_vm_ip: "{{ global_vm_info.instance.ipv4 }}" var_vm_domain: "{{ global_vm_info.customization.domain }}" var_vm_fqdn: "{{ global_vm_info.customization.hostname }}" var_vm_dnsservers: "{{ global_vm_info.customization.dns_servers }}"
注意:此方法会将变量持久化到本地,可能影响后续Playbook执行,优先使用方法一。
内容的提问来源于stack exchange,提问作者slekkus
相关产品推荐
相关产品推荐

