You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 16:09:16