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

Phi*_*ord 12 ansible

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

vars/
    app1.yml
    app2.yml
Run Code Online (Sandbox Code Playgroud)

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

name: app1
git_repo: https://github.com/philgyford/app1.git
# ...
Run Code Online (Sandbox Code Playgroud)

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

apps:
  - name: app1
    git_repo: https://github.com/philgyford/app1.git
    # ...
  - name: app2
    git_repo: https://github.com/philgyford/app2.git
    # ...
Run Code Online (Sandbox Code Playgroud)

即,它将文件中的变量合并为一个.

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

- name: Load var files
  with_fileglob:
    - ../vars/*.yml
  include_vars: '{{ item }}'
Run Code Online (Sandbox Code Playgroud)

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

如果这是制作这样的东西的唯一方法,我愿意稍微重新排列.

udo*_*dan 9

你不能这样做.变量将始终覆盖具有相同名称的变量.你可以用这个确切的设置做的唯一事情是编写你自己的vars插件,它读取这些文件并将它们合并到一个数组中.

如果您愿意更改应用程序定义的结构,则可以使用哈希并设置您的hash_behavior=merge.在每个vars文件中,您将有一个定义,如:

apps:
  app1:
    git_repo: https://github.com/philgyford/app1.git
Run Code Online (Sandbox Code Playgroud)
apps:
  app2:
    git_repo: https://github.com/philgyford/app2.git
Run Code Online (Sandbox Code Playgroud)

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

apps:
  app1:
    git_repo: https://github.com/philgyford/app1.git
  app2:
    git_repo: https://github.com/philgyford/app2.git</pre>
Run Code Online (Sandbox Code Playgroud)

但请注意,hash_behavior=merge从根本上改变了Ansible在全局范围内的默认行为.确保您的所有角色都没有此设置的问题.文件提到:

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

如果您仍然使用Ansible 1,则可以使用我的旧插件之一:include_vars_merged.基本上,这只会将行为添加hash_behavior=merge到单个任务中.

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

  • 在Ansible 2中,您可以使用[`combine`](http://docs.ansible.com/ansible/playbooks_filters.html#combining-hashes-dictionaries)Jinja过滤器,但它确实需要您知道要组合的哈希值在前面 (2认同)
  • 我在这个过滤器中有很多希望,但不幸的是你不能用它来扩展哈希并用相同的名称存储结果.`some_hash:"{{some_hash | combine({foo:bar})}}"`_This_会很有用. (2认同)

小智 6

好吧,你不能直接构建一个数组,但是你可以用一个 dict 来实现同样的努力。

假设你想构造一个数组:

[{
    name: 'bob',
    age: 30
}, {
    name: 'alice',
    age: 35 
}]
Run Code Online (Sandbox Code Playgroud)

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

鲍勃.yml

bob:
  name: bob
  age: 30
Run Code Online (Sandbox Code Playgroud)

爱丽丝.yml

alice:
  name: alice
  age: 35
Run Code Online (Sandbox Code Playgroud)

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

- name: Include vars
  include_vars:
    name: users
    dir: user
Run Code Online (Sandbox Code Playgroud)

这会给你一个 dict users

users:
  alice:
    name: alice
    age: 35
  bob:
    name: bob
    age: 30
Run Code Online (Sandbox Code Playgroud)

dict2items在ansible中使用过滤器,你得到你想要的数组


Vla*_*tka 6

使用属性名称并将包含的变量放入字典中。根据您的需要调整词典名称。例如

    - name: Load var files
      include_vars:
        file: "{{ item }}"
        name: "incl_vars_{{ item|basename|splitext|first }}"
      with_fileglob:
        - vars/*.yml
Run Code Online (Sandbox Code Playgroud)

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

    - set_fact:
        apps: "{{ apps|default([]) + [lookup('vars', item)] }}"
      loop: "{{ query('varnames', '^incl_vars_(.*)$') }}"
Run Code Online (Sandbox Code Playgroud)

给出

apps:
  - git_repo: https://github.com/philgyford/app2.git
    name: app2
  - git_repo: https://github.com/philgyford/app1.git
    name: app1
Run Code Online (Sandbox Code Playgroud)

如果需要,您可以将列表转换为字典

    - set_fact:
        apps: "{{ dict(_keys|zip(apps)) }}"
      vars:
        _keys: "{{ apps|map(attribute='name')|list }}"
Run Code Online (Sandbox Code Playgroud)

给出

apps:
  app1:
    git_repo: https://github.com/philgyford/app1.git
    name: app1
  app2:
    git_repo: https://github.com/philgyford/app2.git
    name: app2
Run Code Online (Sandbox Code Playgroud)