在Ansible中,如何将来自单独文件的变量组合成一个数组?

时间:2016-02-22 13:01:39

标签: ansible

在Ansible,在角色中,我有这样的vars文件:

vars/
    app1.yml
    app2.yml

每个文件都包含特定于应用程序/网站的变量,如下所示:

name: app1
git_repo: https://github.com/philgyford/app1.git
# ...

理想情况下,如果没有预先知道哪些应用程序具有可变文件的任务,我想最终得到一个名为apps的数组,如下所示:

apps:
  - name: app1
    git_repo: https://github.com/philgyford/app1.git
    # ...
  - name: app2
    git_repo: https://github.com/philgyford/app2.git
    # ...

即将文件中的变量合并为一个。

我知道我可以像这样加载所有变量文件:

- name: Load var files
  with_fileglob:
    - ../vars/*.yml
  include_vars: '{{ item }}'

但鉴于每个文件具有相同的变量名称,它将覆盖每个先前的变量集。我无法看到加载变量并将它们放入apps数组的方法。

我愿意稍微重新安排事情,如果这是使这样的事情成为可能的唯一方法。

8 个答案:

答案 0 :(得分:7)

你做不到。变量将始终覆盖具有相同名称的变量。对于这个确切的设置,你唯一能做的就是write your own vars plugin读取这些文件并将它们合并到一个数组中。

如果您愿意更改应用定义的结构,则可以使用哈希和set your hash_behavior=merge。在每个vars文件中,您将有一个如下定义:

time == '2016-02-22
2016-02-22 00:00:00

当Ansible加载两个文件时,它会自动将它们合并到:

apps:
  app1:
    git_repo: https://github.com/philgyford/app1.git

但请注意,apps: app2: git_repo: https://github.com/philgyford/app2.git 从根本上改变了Ansible在全局范围内的默认行为。确保您的所有角色都没有此设置的问题。文件提到:

  

除非您认为绝对需要,否则我们通常建议您不要使用此设置

如果您仍然使用Ansible 1,则可以使用我的旧插件之一:include_vars_merged。基本上,这会将apps: app1: git_repo: https://github.com/philgyford/app1.git app2: git_repo: https://github.com/philgyford/app2.git</pre> 的行为添加到单个任务中。

我还没有考虑将其迁移到Ansible 2,目前看起来我不再需要它了。

答案 1 :(得分:1)

从Ansible v2.0开始,您可以执行以下操作:

- name: merging hash_a and hash_b into hash_c
  set_fact: hash_c="{{ hash_a|combine(hash_b) }}"

在Ansible过滤器下检查更多内容-组合哈希/字典(来自Jinja2)

答案 2 :(得分:1)

使用属性name并将包含的变量放入字典中。使字典的 name 满足您的需求。例如

    - name: Load var files
      include_vars:
        file: "{{ item }}"
        name: "{{ 'incl_vars_' ~ item|basename|splitext|first }}"
      with_fileglob:
          - vars/*.yml

然后,使用查找插件varnames(版本2.8中的新增功能),找到所有词典,然后迭代该列表。在循环中,使用查找插件var(2.5版中的新增功能)并创建列表。例如

    - set_fact:
        my_vars: "{{ my_vars|default([]) + [lookup('vars', item)] }}"
      loop: "{{ query('varnames', '^incl_vars_(.*)$') }}"

    - debug:
        var: my_vars

给予

  my_vars:
  - git_repo: https://github.com/philgyford/app2.git
    name: app2
  - git_repo: https://github.com/philgyford/app1.git
    name: app1

答案 3 :(得分:0)

RewriteRule以来,Ansible 2.2link)模块已经扩展了很多。

现在可以执行以下操作:

include_vars

- include_vars: name: 'apps' dir: '../vars' extensions: - 'yaml' - 'yml' 是关键。在模块页面上:

  

将包含的变量分配给的变量的名称。如果省略(为空),它们将成为顶级变量。

这允许您转换:

name

app1.yml:

vars/
    app1.yml
    app2.yml
    ...

app2.yml:

name: app1
git_repo: https://github.com/philgyford/app1.git
# ...

进入...

name: app2
git_repo: https://github.com/philgyford/app2.git
# ...

答案 4 :(得分:0)

好吧,您不能直接构建数组,但是可以通过dict达到相同的效果。

假设您要构造一个数组:

[{
    name: 'bob',
    age: 30
}, {
    name: 'alice',
    age: 35 
}]

您可以将每个元素放在文件中,例如:

bob.yml

bob:
  name: bob
  age: 30

alice.yml

alice:
  name: alice
  age: 35

将这些文件放在相同的目录中(例如user),然后使用include_vars加载整个目录:

- name: Include vars
  include_vars:
    name: users
    dir: user

这会给你一个字典users

users:
  alice:
    name: alice
    age: 35
  bob:
    name: bob
    age: 30

使用dict2items过滤器,您将获得所需的数组

答案 5 :(得分:0)

想要通过获取与模式匹配的变量列表来发布可能的替代解决方案,那么您就可以处理所有这些变量,进行手动合并。

以下代码块提供了一个示例,该示例提取与特定模式匹配的所有变量并进行循环。您可以合并它们来设置一个新事实,也可以简单地单独处理它们。

- name: "debug2"   debug:
    msg: "value is: {{ lookup('vars', item) }} "   
  loop: "{{ hostvars[inventory_hostname] | select('match', '^linux_hosts_entries') |list  }}"

有关更多详细信息,请参见以下post

答案 6 :(得分:0)

如果您不想更改哈希的默认行为。我建议你我的解决方案。 当Ineed合并它们时,我定义了多个变量(具有相同的正则表达式),并从hostvars中过滤掉它们。例如:

- name: Combine variables with prefix enabled_services
  debug:
    msg: "{{ hostvars[inventory_hostname].keys() | map('regex_search', 'enabled_services.*') | select('string') | list }}"

答案 7 :(得分:0)

我用过这个:

- name: Load data
  run_once: true
  set_fact:
    my_data: "{{ my_data|default([]) + [lookup('file', item) | from_yaml] }}"
  with_fileglob: "../data/*.yml" # relative to this file