如何为所有播放/主机设置 Ansible 变量?

问题描述 投票:0回答:6

这个问题没有答案。有人提到环境变量。能详细说明一下吗?

这看起来是一个简单的问题,但在 ansible 中却不是。它不断出现。特别是在错误情况下。 我需要一个全局变量。我可以在处理一台主机播放时设置一个,然后稍后与另一台主机进行检查。简而言之,这样我就可以根据变量在剧本中稍后进行分支。

我们无法控制自定义软件的安装,但如果安装了,我们就必须将不同的软件放在其他机器上。最重要的是,安装会根据虚拟机文件夹的不同而有所不同。我的全球变体王国。

变量的范围仅与当前 ansible_hostname 相关。是的,我们将 group_vars/all.yml 作为全局变量,但我们无法在游戏中设置它们。如果我设置一个变量,其他主机的播放/任务就看不到它。我了解变量的范围,但我想设置一个可以在所有剧本播放中读取的全局变量。 实际实现并不重要,但变量访问很(重要)。

我的问题:有没有办法设置一个变量,以便在另一台主机上运行不同的任务时可以检查该变量?像 setGlobalSpaceVar(myvar, true) 这样的东西?我知道没有这样的方法,但我正在寻找解决方法。改写:在一个主机的一个任务中设置一个变量,然后在另一台主机的另一个任务中读取该变量。

我能想到的唯一方法是更改控制器上的文件,但这似乎是假的。

一个例子

以下内容涉及 Oracle 备份和本地可执行文件,但我将其保持通用。对于下面的内容 - 是的,我可以执行 run_once,但这不能回答我的问题。 这个变量访问问题在不同的上下文中不断出现。

我有 4 个 xyz 服务器。我有 2 个程序需要执行,但只在两台不同的机器上执行。我不知道是哪一个。对于不同的虚拟机环境,设置可能会有所不同。

我们的programOne在具有驱动器E的服务器上运行。我可以使用ansible找到哪个服务器具有驱动器E,并在每次设置变量(driveE_machine)时进行相应的播放。它仅适用于该主机。为此,其他 3 台机器不会设置driveE_machine。 在稍后的游戏中,我需要仅在其他 3 台机器中的一台上执行另一个程序。这意味着我需要设置一个变量,该变量可以被未运行第二个程序的其他两台主机读取。 我不知道该怎么做。

库存档案:

[xyz]
serverxyz[1:4].private.mystuff

剧本示例:

---
- name: stackoverflow variable question
  hosts: xyz
  gather_facts: no
  serial: 1
  tasks:
      - name: find out who has drive E
         win_shell: dir e:\
         register: adminPage
         ignore_errors: true

       # This sets a variable that can only be read for that host
      - name: set fact driveE_machine when rc is 0
        set_fact:
           driveE_machine: "{{inventory_hostname}}"
        when: adminPage.rc == 0

       - name: run program 1
         include: tasks/program1.yml
         when: driveE_machine is defined

       # program2.yml executes program2 and needs to set some kind of variable
       # so this include can only be executed once for the other 3 machines 
       # (not one that has driveE_machine defined and ???
       - name: run program 2
         include: tasks/program2.yml
         when: driveE_machine is undefined and ???
         # please don't say run_once: true - that won't solve my variable access question

有没有办法设置一个变量,以便在另一台主机上运行任务时可以检查该变量?

ansible
6个回答
25
投票

不确定你真正想要什么,但你可以使用单个循环任务为游戏中的每个主机设置一个事实(全局变量的一些模拟):

playbook.yml

---
- hosts: mytest
  gather_facts: no
  vars:
  tasks:
    # Set myvar fact for every host in a play
    - set_fact:
        myvar: "{{ inventory_hostname }}"
      delegate_to: "{{ item }}"
      with_items: "{{ play_hosts }}"
      run_once: yes
    # Ensure that myvar is a name of the first host
    - debug:
        msg: "{{ myvar }}"

主持人

[mytest]
aaa ansible_connection=local
bbb ansible_connection=local
ccc ansible_connection=local

结果

PLAY [mytest] ******************
META: ran handlers

TASK [set_fact] ******************
ok: [aaa -> aaa] => (item=aaa) => {"ansible_facts": {"myvar": "aaa"}, "ansible_facts_cacheable": false, "changed": false, "failed": false, "item": "aaa"}
ok: [aaa -> bbb] => (item=bbb) => {"ansible_facts": {"myvar": "aaa"}, "ansible_facts_cacheable": false, "changed": false, "failed": false, "item": "bbb"}
ok: [aaa -> ccc] => (item=ccc) => {"ansible_facts": {"myvar": "aaa"}, "ansible_facts_cacheable": false, "changed": false, "failed": false, "item": "ccc"}

TASK [debug] ******************
ok: [aaa] => {
    "msg": "aaa"
}
ok: [bbb] => {
    "msg": "aaa"
}
ok: [ccc] => {
    "msg": "aaa"
}

6
投票

https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#fact-caching

如文档中其他地方所示,一台服务器可以引用另一台服务器的变量,如下所示:

{{ hostvars['asdf.example.com']['ansible_os_family'] }}

这甚至适用于在剧本中动态设置的变量。


1
投票

这个答案并不预先假设您的主机名,也不预先假设有多少主机有“驱动器 E:”。它将选择第一个可访问且具有“驱动器 E:”的驱动器。我没有 Windows 盒子,所以我通过随机抛硬币来判断主机是否这样做;你当然可以使用你原来的

win_shell
任务,我已经注释掉了。

---

- hosts: all
  gather_facts: no
  # serial: 1
  tasks:
    # - name: find out who has drive E
    #   win_shell: dir e:\
    #   register: adminPage
    #   ignore_errors: true

    - name: "Fake finding hosts with drive E:."
      # I don't have hosts with "drive E:", so fake it.
      shell: |
        if [ $RANDOM -gt 10000 ] ; then
            exit 1
        else
            exit 0
        fi
      args:
        executable: /bin/bash
      register: adminPage
      failed_when: false
      ignore_errors: true
      
    - name: "Dict of hosts with E: drives."
      run_once: yes
      set_fact:
        driveE_status: "{{ dict(ansible_play_hosts_all |
                            zip(ansible_play_hosts_all |
                                map('extract', hostvars, ['adminPage', 'rc'] ) | list
                               ))
                        }}"

    - name: "List of hosts with E: drives."
      run_once: yes
      set_fact:
        driveE_havers: "{%- set foo=[] -%}
                        {%- for dE_s in driveE_status -%}
                           {%- if driveE_status[dE_s] == 0 -%}
                             {%- set _ = foo.append( dE_s ) -%}
                           {%- endif -%}
                        {%- endfor -%}{{ foo|list }}"                                     

    - name: "First host with an E: drive."
      run_once: yes
      set_fact:
        driveE_first: "{%- set foo=[] -%}
                        {%- for dE_s in driveE_status -%}
                           {%- if driveE_status[dE_s] == 0 -%}
                             {%- set _ = foo.append( dE_s ) -%}
                           {%- endif -%}
                        {%- endfor -%}{{ foo|list|first }}"                                     

    - name: Show me.
      run_once: yes
      debug:
        msg:
          - "driveE_status: {{ driveE_status }}"
          - "driveE_havers: {{ driveE_havers }}"
          - "driveE_first: {{ driveE_first }}"

0
投票

我采取了不同的方法:

  • 在每个主机上设置事实
  • 将所有事实同步到第一主机

以下是在所有主机上设置相同生成密码的示例:

  - name: Generate a password
    set_fact:
      configure_user_password: "{{
        lookup(
          'ansible.builtin.password',
          '/dev/null',
          chars=[
            'ascii_letters',
            'digits'
          ],
          length=12
        )
      }}"

  - debug:
      var: configure_user_password

  - name: Synchronize generated passwords
    set_fact:
      configure_user_password: "{{
        (
          hostvars
          | dict2items
          | selectattr(
            'value.configure_user_password',
            'defined'
          )
          | map(attribute='value.configure_user_password')
          | list
        )
          [0]
      }}"

  - debug:
      var: configure_user_password

-1
投票

这对我有用,你可以直接使用register var,不需要使用set_fact。

---
- hosts: manager
  tasks:
    - name: dir name
      shell: cd /tmp && pwd
      register: homedir
      when: "'manager' in group_names"

- hosts: all
  tasks:
    - name: create a test file
      shell: touch "{{hostvars['manager.example.io'['homedir'].stdout}}/t1.txt"

-1
投票

我在ansible任务提示菜单中使用了“set_fact”模块,这有助于将用户输入传递到所有清单主机中。

#监控手册 
- 主持人:全部
  收集事实:是的
  变成:是

  任务:
    - 暂停:
        迅速的: ”

您想要执行哪种监控?

--------------------------------------

1.内存利用率:
2.CPU利用率:
3. 文件系统实用程序
化:
4. 从 Playbook 中存在: 
5. 获取Nmon报告 
 
请选择选项: 
--------------------------------------
”
      注册:菜单

    - 设置事实:
        选项:“{{menu.user_input}}”
      delegate_to:“{{项目}}”
      with_items:“{{ play_hosts }}”
      运行一次:是的

#1 内存监控

    - 暂停:
        迅速的: ”
-------------------------------------- 
 输入监控事件编号 = "
      注册:事件_编号_结果
      当:选项==“1”

    - 名称:标准化 event_number 变量
      设置事实:
        Incident_number:“{{ Incident_number_result.user_input }}”
      当:选项==“1”
      delegate_to:“{{项目}}”
      with_items:“{{ play_hosts }}”
      运行一次:是的

ansible 剧本结果是

[ansibusr@ansiblemaster monitoring]$ ansible-playbook monitoring.yml

PLAY [all] **************************************************************************

TASK [Gathering Facts] **************************************************************************
ok: [node2]
ok: [node1]
[pause]


Which monitoring you want to perform?

--------------------------------------

1. Memory Utilization:
2. CPU Utilization:
3. Filesystem Utilization:
4. Exist from Playbook:
5. Fetch Nmon Report

Please select option:
--------------------------------------
:

TASK [pause] **************************************************************************
ok: [node1]

TASK [set_fact] **************************************************************************
ok: [node1 -> node1] => (item=node1)
ok: [node1 -> node2] => (item=node2)
[pause]

--------------------------------------
 Enter monitoring Incident Number = :
INC123456
TASK [pause] **************************************************************************
ok: [node1]

TASK [Standardize incident_number variable] ****************************************************************************************************************************
ok: [node1 -> node1] => (item=node1)
ok: [node1 -> node2] => (item=node2)
© www.soinside.com 2019 - 2024. All rights reserved.