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

时间:2018-05-22 21:57:31

标签: ansible ansible-facts

我想使用vars将多个变量传递给任务。目前,我正在执行下面的

vars:
    var1_name: "var1_value"
    var2_name: "var2_value"

随着变量数量的增加,我宁愿使用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"

字典看起来像这样:

"variables": {
    "var1_name": "var1_value",
    "var2_name": "var2_value",
}

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

但是,当我尝试将字典传递给vars时,如下所示

vars: "{{ variables }}"

Ansible抛出错误:

ERROR! Vars in a Play must be specified as a dictionary, or a list of dictionaries

如何在vars中传递字典变量?

3 个答案:

答案 0 :(得分:3)

在对Ansible源代码进行一些搜索之后,即使是Ansible的开发人员也面临着这个问题。在某些集成测试中,由于同样的错误,有一些特定的测试被注释掉了。

ansible /测试/集成/目标/ include_import /角色/ 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 }}"

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

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)

似乎因为“{{}}”实际上只是一个YAML字符串,Ansible不会将其识别为dict,这意味着vars属性没有通过Jinja2引擎传递,而是被评估为什么它实际上是。

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

var: &_anchored_var 
  attr1: "test"
  att2: "bar"

vars:
  <<: *_anchored_var

答案 1 :(得分:1)

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

档案myvars1.yml

myvars:
  var1_name: "var1_value"
  var2_name: "var2_value"

然后读取像

这样的变量
  - 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

之后,请使用:

- name: My Running Module
  mymodule:
    myaction1: "{{ myvars.var1_name }}"
    myaction2: "{{ myvars.var2_name }}"

希望有所帮助

答案 2 :(得分:0)

您可以使用dict查找。

以您的示例为例,我会这样做:

- hosts: localhost
  vars:
    my_vars_dict:
      var1_name: "var1_value"
      var2_name: "var2_value"

  tasks:
    - debug:
        msg: "Key: {{ item.key }} | Value: {{ item.value }}"
      loop: "{{ lookup('dict', my_vars_dict) }}"

输出为:

Key: var2_name | Value: var2_value
Key: var1_name | Value: var1_value

摘自文档:https://docs.ansible.com/ansible/latest/plugins/lookup/dict.html