Ansible多主机执行故障:动态获取主机后无法调用变量
Ansible跨Play无法读取set_fact变量的解决方案
问题描述
我有一个分两部分执行的Ansible脚本:第一部分在localhost执行,查询数据库表以获取主机名;第二部分需要在之前查询得到的主机上运行。但第二部分无法使用第一部分中通过set_fact设置的主机变量。
原实现代码:
- hosts: localhost gather_facts: false become: yes become_user: oracle vars_files: - vars/main.yml tasks: - name: Get new hostname tempfile: state: file register: tf - name: create sql file template: src: get_hostname.sql.j2 dest:"{{ tf.path }}" mode: 0775 - name: login command: argv: - "sqlplus" - -s - "@{{ tf.path }}" environment: ORACLE_HOME: "oracle/home" register: command_out - set_fact: NEW_HOST: "{{ command_out.stdout }}" - hosts: "{{ NEW_HOST }}" gather_facts: false become: yes become_user: oracle vars_file: - vars/main.yml tasks: - name: debug command: hostname register: new_host_out - debug: msg: "new host is {{ new_host_out.stdout }}"
第一部分运行正常,但第二部分报错无法找到NEW_HOST变量。
问题原因
用set_fact设置的变量默认是当前Play目标主机的主机变量(此处为localhost),Ansible的不同Play之间不会自动共享主机变量,因此第二Play无法直接引用NEW_HOST。
解决方案
方案一:通过hostvars直接引用localhost的变量
修改第二Play的hosts字段,从localhost的主机变量中读取目标主机名:
- hosts: localhost gather_facts: false become: yes become_user: oracle vars_files: - vars/main.yml tasks: - name: Get new hostname tempfile: state: file register: tf - name: create sql file template: src: get_hostname.sql.j2 dest:"{{ tf.path }}" mode: 0775 - name: login command: argv: - "sqlplus" - -s - "@{{ tf.path }}" environment: ORACLE_HOME: "oracle/home" register: command_out - set_fact: NEW_HOST: "{{ command_out.stdout | trim }}" # 去除输出中的换行/空格 - hosts: "{{ hostvars['localhost'].NEW_HOST }}" gather_facts: false become: yes become_user: oracle vars_files: # 修正原代码语法错误:vars_file → vars_files - vars/main.yml tasks: - name: debug command: hostname register: new_host_out - debug: msg: "new host is {{ new_host_out.stdout }}"
注意事项:
- 给
command_out.stdout添加| trim过滤器,避免SQL输出的换行或多余空格导致主机名识别失败 - 修正第二Play中的
vars_file为vars_files(原代码的语法错误)
方案二:使用add_host将主机添加到临时Inventory
在第一Play中用add_host把获取到的主机添加到临时组,第二Play直接针对该组执行任务:
- hosts: localhost gather_facts: false become: yes become_user: oracle vars_files: - vars/main.yml tasks: - name: Get new hostname tempfile: state: file register: tf - name: create sql file template: src: get_hostname.sql.j2 dest:"{{ tf.path }}" mode: 0775 - name: login command: argv: - "sqlplus" - -s - "@{{ tf.path }}" environment: ORACLE_HOME: "oracle/home" register: command_out - name: Add target host to temporary group add_host: name: "{{ command_out.stdout | trim }}" groups: temp_target_hosts # 自定义临时组名称 - hosts: temp_target_hosts gather_facts: false become: yes become_user: oracle vars_files: - vars/main.yml tasks: - name: debug command: hostname register: new_host_out - debug: msg: "new host is {{ new_host_out.stdout }}"
该方案更直观,适合后续需要针对目标主机执行多组任务的场景,临时组可重复调用。
内容的提问来源于stack exchange,提问作者Yashwanth Veeranki
相关产品推荐
相关产品推荐

