在Ansible中,如何将不同文件中的变量组合到一个数组中?

在Ansible中,如何将不同文件中的变量组合到一个数组中?,ansible,Ansible,在Ansible中,在一个角色中,我有如下vars文件: vars/ app1.yml app2.yml name: app1 git_repo: https://github.com/philgyford/app1.git # ... apps: - name: app1 git_repo: https://github.com/philgyford/app1.git # ... - name: app2 git_repo: https://

在Ansible中,在一个角色中,我有如下vars文件:

vars/
    app1.yml
    app2.yml
name: app1
git_repo: https://github.com/philgyford/app1.git
# ...
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 }}'
每个文件都包含特定于应用程序/网站的变量,如下所示:

vars/
    app1.yml
    app2.yml
name: app1
git_repo: https://github.com/philgyford/app1.git
# ...
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
的数组,如下所示:

vars/
    app1.yml
    app2.yml
name: app1
git_repo: https://github.com/philgyford/app1.git
# ...
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 }}'
即,将文件中的变量合并为一个变量

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

vars/
    app1.yml
    app2.yml
name: app1
git_repo: https://github.com/philgyford/app1.git
# ...
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
数组的方法


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

你不能这样做。变量将始终覆盖具有相同名称的变量。使用这个精确的设置,您唯一能做的就是读取这些文件并将它们合并到一个数组中

如果您愿意更改应用程序定义的结构,则可以使用哈希和。在每个vars文件中,定义如下:

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

Ansible加载两个文件时,将自动将其合并为:

apps:
  app1:
    git_repo: https://github.com/philgyford/app1.git
  app2:
    git_repo: https://github.com/philgyford/app2.git</pre>
应用程序:
附录1:
吉特回购:https://github.com/philgyford/app1.git
附录2:
吉特回购:https://github.com/philgyford/app2.git
但是请注意,
hash\u behavior=merge
从根本上改变了Ansible在全局级别上的默认行为。确保您的所有角色都没有与此设置相关的问题。文件提到:

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

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


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

自从
Ansible 2.2
以来,
include_vars
()模块已经扩展了很多

现在可以执行以下操作:

- include_vars:
    name: 'apps'
    dir: '../vars'
    extensions:
      - 'yaml'
      - 'yml'
name
是这里的关键。从模块页面:

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

这允许您转换:

vars/
    app1.yml
    app2.yml
    ...
附录1.yml:

name: app1
git_repo: https://github.com/philgyford/app1.git
# ...
附录2.yml:

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

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

从Ansible v2.0开始,您可以:

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

在Ansible filters下查看更多信息-组合哈希/字典(来自Jinja2)

好吧,你不能直接构建数组,但你可以通过dict实现同样的效果

假设要构造一个数组:

[{
    name: 'bob',
    age: 30
}, {
    name: 'alice',
    age: 35 
}]
您可以将每个元素放入一个文件中,如下所示:

鲍勃·伊梅尔 艾丽丝·伊梅尔 将这些文件放在同一目录中(例如,
user
),然后使用
include\u vars
加载整个目录:

- name: Include vars
  include_vars:
    name: users
    dir: user
这将为您提供一个dict
用户

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

使用ansible中的
dict2items
过滤器,您可以通过获取与模式匹配的变量列表来获得所需数组

想要发布可能的替代解决方案,然后您可以只处理所有这些变量,或手动合并

下面的代码块给出了一个示例,用于提取与特定模式和循环匹配的所有变量。您可以设置一个新的事实,合并它们,或者简单地单独处理它们

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

有关详细信息,请参阅以下内容。

如果不想更改哈希的默认行为。我建议你我的解决办法。 我定义了多个变量(使用相同的正则表达式),当我需要合并它们时,我从hostvars中过滤它们。例如:

- name: Combine variables with prefix enabled_services
  debug:
    msg: "{{ hostvars[inventory_hostname].keys() | map('regex_search', 'enabled_services.*') | select('string') | list }}"
使用属性并将包含的变量放入字典中。使词典的名称符合您的需要。比如说

-名称:加载var文件
包括以下变量:
文件:“{{item}}”
名称:{{'incl_vars}~item | basename | splitext | first}
使用_fileglob:
-vars/*.yml
然后,使用查找插件(版本2.8中新增),查找所有字典,并迭代列表。在循环中使用查找插件(2.5版中新增)并创建应用列表。比如说

-设置事实:
应用程序:{{apps}默认值([])+[lookup('vars',item)]}
循环:“{query('varnames','^incl_vars.*)$”}”
-调试:
变量:应用程序
给予

应用程序:
-吉特回购:https://github.com/philgyford/app2.git
姓名:app2
-吉特回购:https://github.com/philgyford/app1.git
名称:app1
我用过这个:

- 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

在Ansible 2中,您可以使用Jinja筛选器,但它确实要求您知道要合并的哈希值frontI对此筛选器抱有很大希望,但不幸的是,您无法使用它扩展哈希值并以相同的名称存储结果
somehash:“{{somehash}combine({foo:bar}}}}”
这会很有用。谢谢。我担心没有简单的答案——我会找到其他不那么好的方法来处理这些VAR。我曾遇到过
hash\u behavior=merge
,但考虑到这会极大地改变Ansible的行为,我还是很谨慎。同时,联合收割机也提高了我的希望,但很快就破灭了。如此接近……如果你从一个干净的剧本开始,你可以加载一组变量,然后从
hostvars
字典将它们加载到你的目标字典中,过滤掉以
ansible
库存
模块
省略
开头的任何键,和
剧本
。在第二步中,也要过滤掉你的目标字典。“你不能这么做……你唯一能做的就是编写你自己的vars插件,读取这些文件并将它们合并到一个数组中。”这句话是错误的。看看我的答案你试过你发布的解决方案吗?因为Ansible不接受vars文件作为列表,所以它必须是字典。会的。如果要合并两个子数组呢?比如说