Ansible Playbook中hosts字段引用前置Play变量失败的问题
Ansible Playbook hosts字段变量未定义问题排查与解决
我有一个用于在MySQL数据库执行SQL的Ansible Playbook,会先导入init.yml(该剧本会设置包括mysql_config_master在内的变量)。当在hosts字段使用newsp:!*:&{{ mysql_config_master }}筛选主机时,报错提示mysql_config_master未定义;但将hosts改为newsp后,debug任务可正常输出该变量的值。希望直接在hosts字段指定目标主机,而非使用when条件或新增主机组,寻求问题原因及解决办法。
报错版本Playbook
--- # This playbook sets a bunch facts/variables # including mysql_config_master. - import_playbook: init.yml - name: Create Config Database hosts: newsp:!*:&{{ mysql_config_master }} gather_facts: True become: True tasks: - name: Debug MySql Config Master debug: var: mysql_config_master
报错信息
ERROR! The field 'hosts' has an invalid value, which includes an undefined variable. The error was: 'mysql_config_master' is undefined The error appears to be in '/home/red/GIT/ansible/playbooks/create_sp_config_db.yml': line 5, column 3, but may be elsewhere in the file depending on the exact syntax problem. The offending line appears to be: - name: Create sp_config Database ^ here
可正常运行的Playbook版本
--- # This playbook sets a bunch facts/variables # including mysql_config_master. - import_playbook: init.yml - name: Create Config Database hosts: newsp gather_facts: True become: True tasks: - name: Debug MySql Config Master debug: var: mysql_config_master
Debug输出结果
TASK [Debug MySql Config Master] ********************************************************************************************************************************************************************************************************************************* Tuesday 21 November 2023 14:06:13 -0800 (0:00:02.244) 0:00:22.827 ****** Tuesday 21 November 2023 14:06:13 -0800 (0:00:02.244) 0:00:22.824 ****** ok: [sandbox-xo-dmz1.pl.example.com] => { "mysql_config_master": "sandbox-xo-dmz1.pl.example.com" } ok: [sandbox-xo-dmz2.pl.example.com] => { "mysql_config_master": "sandbox-xo-dmz1.pl.example.com" } ok: [sandbox-xo-arb.pl.example.com] => { "mysql_config_master": "sandbox-xo-dmz1.pl.example.com" } ok: [sandbox-xo-rtp1.pl.example.com] => { "mysql_config_master": "sandbox-xo-dmz1.pl.example.com" }
备选方案(不希望使用)
- name: Create Config Database hosts: newsp gather_facts: True become: True tasks: - name: Debug MySql Config Master debug: var: mysql_config_master when: inventory_hostname == mysql_config_master
init.yml内容
--- - name: Pre gather facts for all hosts hosts: all gather_facts: true - name: Set variables based on the hostvars hosts: cluster,aws, monitor gather_facts: false become: true roles: - roles/libs/set_sp_vars - name: Set sp_srv based on the hostvars hosts: sp,newsp,monitor gather_facts: false become: true roles: - roles/libs/set_sp_srv
问题原因
Ansible的Playbook执行分为解析阶段和执行阶段:
- 解析阶段:加载整个Playbook的结构,提前处理所有play的
hosts字段、变量引用等语法逻辑。 - 执行阶段:按顺序运行每个play及其中的任务。
你在hosts字段中使用{{ mysql_config_master }}时,这个变量引用会在解析阶段被处理,但import_playbook: init.yml中设置变量的逻辑是在执行阶段才会运行的。此时变量还未被定义,自然会触发未定义报错。而将hosts改为newsp后,debug任务在执行阶段运行,此时init.yml已经完成变量设置,所以能正常输出变量值。
解决办法
要在hosts字段直接指定目标主机,可通过add_host模块在init.yml中创建临时主机组,后续play直接引用该组:
步骤1:修改init.yml添加临时组逻辑
如果不想修改原有角色,可在init.yml末尾新增一个play,将主节点加入临时组:
- name: 创建MySQL主节点临时组 hosts: newsp gather_facts: false tasks: - name: 将主节点加入临时组 add_host: name: "{{ mysql_config_master }}" groups: mysql_config_master_group run_once: true
步骤2:修改目标Playbook的hosts字段
将原hosts字段改为引用临时组,实现精准筛选:
- name: Create Config Database hosts: newsp:&mysql_config_master_group gather_facts: True become: True tasks: - name: Debug MySql Config Master debug: var: mysql_config_master
这样即可直接在hosts字段定位到目标主机,无需使用when条件。
内容的提问来源于stack exchange,提问作者Red Cricket
相关产品推荐
相关产品推荐

