【问题标题】:Access variable from one role in another role in an Ansible playbook with multiple hosts在具有多个主机的 Ansible 剧本中从一个角色访问另一个角​​色的变量
【发布时间】:2021-03-27 02:15:30
【问题描述】:

我正在使用最新版本的 Ansible,我正在尝试在 role-one 中使用主机 one 上的默认变量,在 role-two 中,在主机 two 上使用,但我不能让它工作。

我在文档或 StackOverflow 上发现的任何内容都没有真正的帮助。我不确定我做错了什么。理想情况下,我想设置一次变量的值,并能够在我的剧本中的任何主机上以另一个角色使用它。

我在下面把它分解了。


在我的清单中,我有一个名为 [test] 的主机组,其中有两个主机别名为 onetwo

[test]
one ansible_host=10.0.1.10 ansible_connection=ssh ansible_user=centos ansible_ssh_private_key_file=<path_to_key>
two ansible_host=10.0.1.20 ansible_connection=ssh ansible_user=centos ansible_ssh_private_key_file=<path_to_key>

我有一个单个剧本,其中每个主机都有一个播放,我为主机one 和@987654332 提供hosts: 值作为"{{ host_group }}[0]" @代表主机two

主持人one 使用一个名为role-one 的角色,而主持人two 使用一个名为role-two 的角色。

- name: Test Sharing Role Variables
  hosts: "{{ host_group }}[0]"
  roles:
    - ../../ansible-roles/role-one

- name: Test Sharing Role Variables
  hosts: "{{ host_group }}[1]"
  roles:
    - ../../ansible-roles/role-two  

role-one我设置了一个变量variable-one

---
# defaults file for role-one

variable_one: Role One Variable

我想在role-two 的模板中使用variable_one 的值,但我没有运气。我在role-two 中使用以下作为任务来测试变量是否被“拾取”。

---
# tasks file for role-two
- debug:
    msg: "{{ variable_one }}"

当我使用 ansible-playbook test.yml --extra-vars "host_group=test" 运行剧本时,出现以下故障。

TASK [../../ansible-roles/role-two : debug] ***********************************************************************************************************************************************************************************************
fatal: [two]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: \"hostvars['test']\" is undefined\n\nThe error appears to be in 'ansible-roles/role-two/tasks/main.yml': line 3, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n# tasks file for role-two\n- debug:\n  ^ here\n"}

【问题讨论】:

    标签: ansible


    【解决方案1】:

    问:在具有多个主机的 Ansible playbook 中,从一个角色访问另一个角​​色的变量

    A:简短回答:使用 set_fact 并将变量放入 hostvars

    详细信息:给定角色

    shell> cat roles/role-one/defaults/main.yml 
    variable_one: Role One Variable
    
    shell> cat roles/role-one/tasks/main.yml 
    - debug:
        var: variable_one
    
    shell> cat roles/role-two/tasks/main.yml 
    - debug:
        var: variable_one
    

    剧本

    - hosts: one
      roles:
        - role-one
      tasks:
        - debug:
            var: variable_one
    
    - hosts: two
      roles:
        - role-two
    
    - hosts: one
      tasks:
        - debug:
            var: variable_one
    

    给予(删节)

    PLAY [one] ************************************************
    
    TASK [role-one : debug] ****
    ok: [one] => 
      variable_one: Role One Variable
    
    TASK [debug] ****
    ok: [one] => 
      variable_one: Role One Variable
    
    PLAY [two] ************************************************
    
    TASK [role-two : debug] ****
    ok: [two] => 
      variable_one: VARIABLE IS NOT DEFINED!
    
    PLAY [one] ************************************************
    
    TASK [debug] ****
    ok: [one] => 
      variable_one: VARIABLE IS NOT DEFINED!
    

    正如预期的那样,变量 variable_one 对第一次播放中的任务是可见的。但是,没有理由在第二场比赛中该变量应该对主机 two 可见。在第三次播放中,该变量对同一主机也不可见,因为它尚未存储在 hostvars 中,即“实例化”。下面的剧本

    - hosts: one
      roles:
        - role-one
      tasks:
        - debug:
            var: variable_one
        - set_fact:
            variable_one: "{{ variable_one }}"
    
    - hosts: two
      roles:
        - role-two
    
    - hosts: one
      tasks:
        - debug:
            var: variable_one
    

    给予(删节)

    PLAY [one] ************************************************
    
    TASK [role-one : debug] ****
    ok: [one] => 
      variable_one: Role One Variable
    
    TASK [debug] ****
    ok: [one] => 
      variable_one: Role One Variable
    
    TASK [set_fact] ****
    ok: [one]
    
    PLAY [two] ************************************************
    
    TASK [role-two : debug] ****
    ok: [two] => 
      variable_one: VARIABLE IS NOT DEFINED!
    
    PLAY [one] ************************************************
    
    TASK [debug] ****
    ok: [one] => 
      variable_one: Role One Variable
    

    现在,该变量对整个 playbook 中的主机 one 可见,并且也可以使用 hostvars 对其他主机可见。例如下面的剧本

    - hosts: one
      roles:
        - role-one
      tasks:
        - debug:
            var: variable_one
        - set_fact:
            variable_one: "{{ variable_one }}"
    
    - hosts: two
      tasks:
        - set_fact:
            variable_one: "{{ hostvars.one.variable_one }}"
        - include_role:
            name: role-two
    

    给予(删节)

    PLAY [one] ************************************************
    
    TASK [role-one : debug] ****
    ok: [one] => 
      variable_one: Role One Variable
    
    TASK [debug] ****
    ok: [one] => 
      variable_one: Role One Variable
    
    TASK [set_fact] ****
    ok: [one]
    
    PLAY [two] ************************************************
    
    TASK [set_fact] ****
    ok: [two]
    
    TASK [include_role : role-two] ****
    
    TASK [role-two : debug] ****
    ok: [two] => 
      variable_one: Role One Variable
    

    上述设置的问题是引用 hostvars 的主机是硬编码的。更好的方法是在所有主机的第一次播放中“实例化”变量。例如,为角色添加一个虚拟任务

    shell> cat roles/role-one/tasks/noop.yml
    - meta: noop
    

    然后,在第一个游戏中,包含所有主机,run_once 导入角色,只运行虚拟任务,并为所有主机“实例化”变量。例如

    - hosts: all
      tasks:
        - import_role:
            name: role-one
            tasks_from: noop.yml
          run_once: true
        - set_fact:
            variable_one: "{{ variable_one }}"
          run_once: true
    
    - hosts: two
      roles:
        - role-two
    
    - hosts: one
      roles:
        - role-two
    

    给予(删节)

    PLAY [all] ************************************************
    
    TASK [set_fact] ****
    ok: [one]
    
    PLAY [two] ************************************************
    
    TASK [role-two : debug] ****
    ok: [two] => 
      variable_one: Role One Variable
    
    PLAY [one] ************************************************
    
    TASK [role-two : debug] ****
    ok: [one] => 
      variable_one: Role One Variable
    

    【讨论】:

      【解决方案2】:

      在角色中声明的变量的作用域是剧。如果您想在role-two 中访问来自role-one 的变量,则它们都需要在同一个游戏中。例如,你可以这样写:

      - name: Test Sharing Role Variables
        hosts: "{{ host_group }}"
        tasks:
          - import_role:
              name: role-one
            when: inventory_hostname == "one"
      
          - import_role:
              name: role-two
            when: inventory_hostname == "two"
      

      或者,您可以重组您的角色,以便可以将变量与您的操作分开导入。也就是说,拥有一个除了定义变量什么都不做的role_one_vars 角色,然后您可以在role-onerole-two 中导入它。也就是说,你会有一个类似这样的结构:

      playbook.yml
      hosts
      roles/
        role-one/
          tasks/
            main.yml
        role-one-vars/
          variables/
            main.yml
        role-two/
          tasks/
            main.yml
      

      role-one/tasks/main.yml 看起来像:

      - import_role:
          name: role-one-vars
      
      - debug:
          msg: "in role-one: {{ variable_one }}"
      

      role-two/tasks/main.yml 看起来像:

      ---
      - import_role:
          name: role-one-vars
      
      - debug:
          msg: "in role-two: {{ variable_one }}"
      

      role-one-vars/vars/main.yml 看起来像:

      ---
      variable_one: role one variable
      

      将所有这些放在一起,输出如下所示:

      
      PLAY [Test Sharing Role Variables] *****************************************************************************************************************************************
      
      TASK [Gathering Facts] *****************************************************************************************************************************************************
      ok: [one]
      
      TASK [role-one : debug] ****************************************************************************************************************************************************
      ok: [one] => {
          "msg": "in role-one: role one variable"
      }
      
      PLAY [Test Sharing Role Variables] *****************************************************************************************************************************************
      
      TASK [Gathering Facts] *****************************************************************************************************************************************************
      ok: [two]
      
      TASK [role-two : debug] ****************************************************************************************************************************************************
      ok: [two] => {
          "msg": "in role-two: role one variable"
      }
      
      PLAY RECAP *****************************************************************************************************************************************************************
      one                        : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
      two                        : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
      

      【讨论】:

      • 这是一个非常方便的答案。谢谢
      猜你喜欢
      • 2015-06-04
      • 2015-07-31
      • 2018-08-03
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 2017-01-06
      • 1970-01-01
      • 2020-11-02
      相关资源
      最近更新 更多