如何在 vars 中使用已注册 ansible 变量的字典?

use*_*551 10 ansible ansible-facts

我想使用vars. 目前,我正在做如下

vars:
    var1_name: "var1_value"
    var2_name: "var2_value"
Run Code Online (Sandbox Code Playgroud)

由于变量的数量可以增加,我宁愿使用vars. 我已经构建了一个变量字典,如下所示

- name: set fact
  hosts: localhost
  tasks:
  - set_fact:
      variables: "{{ variables|default({}) | combine( {item.variable: item.value} ) }}"
    with_items:
    - variable: var1_name
      value: "var1_value"
    - variable: var2_name
      value: "var2_name"
Run Code Online (Sandbox Code Playgroud)

字典看起来像这样:

"variables": {
    "var1_name": "var1_value",
    "var2_name": "var2_value",
}
Run Code Online (Sandbox Code Playgroud)

现在,我想让这个字典中的变量可用于在其他主机上执行的角色。

但是,当我试图通过字典来vars喜欢下面

vars: "{{ variables }}"
Run Code Online (Sandbox Code Playgroud)

Ansible 抛出错误:

ERROR! Vars in a Play must be specified as a dictionary, or a list of dictionaries
Run Code Online (Sandbox Code Playgroud)

如何传入字典变量vars

leb*_*b4r 11

在对 Ansible 源代码进行了一些搜索之后,看起来这甚至是 Ansible 的开发人员都面临的问题。在一些集成测试中,有一些特定的测试因为同样的错误而被注释掉。

ansible/tests/integration/targets/include_import/role/test_include_role.yml

        ## FIXME Currently failing with
        ## ERROR! Vars in a IncludeRole must be specified as a dictionary, or a list of dictionaries
        # - name: Pass all variables in a variable to role
        #   include_role:
        #     name: role1
        #     tasks_from: vartest.yml
        #   vars: "{{ role_vars }}"
Run Code Online (Sandbox Code Playgroud)

我还发现这是被调用以包含变量的基础函数:

    def _load_vars(self, attr, ds):
            '''
            Vars in a play can be specified either as a dictionary directly, or
            as a list of dictionaries. If the later, this method will turn the
            list into a single dictionary.
            '''
    
            def _validate_variable_keys(ds):
                for key in ds:
                    if not isidentifier(key):
                        raise TypeError("'%s' is not a valid variable name" % key)
    
            try:
                if isinstance(ds, dict):
                    _validate_variable_keys(ds)
                    return combine_vars(self.vars, ds)
                elif isinstance(ds, list):
                    all_vars = self.vars
                    for item in ds:
                        if not isinstance(item, dict):
                            raise ValueError
                        _validate_variable_keys(item)
                        all_vars = combine_vars(all_vars, item)
                    return all_vars
                elif ds is None:
                    return {}
                else:
                    raise ValueError
            except ValueError as e:
                raise AnsibleParserError("Vars in a %s must be specified as a dictionary, or a list of dictionaries" % self.__class__.__name__,
                                         obj=ds, orig_exc=e)
            except TypeError as e:
                raise AnsibleParserError("Invalid variable name in vars specified for %s: %s" % (self.__class__.__name__, e), obj=ds, orig_exc=e)
Run Code Online (Sandbox Code Playgroud)

似乎因为 "{{ }}" 实际上只是一个 YAML 字符串,Ansible 不会将其识别为 dict,这意味着 vars 属性没有通过 Jinja2 引擎传递,而是根据它的实际情况进行评估.

传递 YAML 对象的唯一方法是使用锚点,但是这需要整个对象而不是动态定义。

    var: &_anchored_var 
      attr1: "test"
      att2: "bar"
    
    vars:
      <<: *_anchored_var
Run Code Online (Sandbox Code Playgroud)


imj*_*gel 1

我建议使用结构化的方式来管理变量,例如:

文件 myvars1.yml

myvars:
  var1_name: "var1_value"
  var2_name: "var2_value"
Run Code Online (Sandbox Code Playgroud)

然后读取变量,例如

  - name: Read all variables
    block:
      - name: Get All Variables
        stat:
          path: "{{item}}"
        with_fileglob:
          - "/myansiblehome/vars/common/myvars1.yml"
          - "/myansiblehome/vars/common/myvars2.yml"
        register: _variables_stat

      - name: Include Variables when found
        include_vars : "{{item.stat.path}}"
        when         : item.stat.exists
        with_items   : "{{_variables_stat.results}}"
        no_log       : true
    delegate_to: localhost
    become: false
Run Code Online (Sandbox Code Playgroud)

之后,使用如下:

- name: My Running Module
  mymodule:
    myaction1: "{{ myvars.var1_name }}"
    myaction2: "{{ myvars.var2_name }}"
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你