在Ansible中合并字典

68 投票
6 回答
110636 浏览
提问于 2025-04-18 18:02

我现在正在用ansible创建一个安装PHP的角色,但在合并字典时遇到了一些困难。我尝试了几种方法,但就是无法达到我想要的效果:

# A vars file:
my_default_values:
  key = value

my_values:
  my_key = my_value


# In a playbook, I create a task to attempt merging the
# two dictionaries (which doesn't work):

- debug: msg="{{ item.key }} = {{ item.value }}"
  with_dict: my_default_values + my_values

# I have also tried:

- debug: msg="{{ item.key }} = {{ item.value }}"
  with_dict: my_default_values|union(my_values)

# I have /some/ success with using j2's update,
# but you can't use j2 syntax in "with_dict", it appears.
# This works:

- debug: msg="{{ my_default_values.update(my_values) }}"

# But this doesn't:

- debug: msg="{{ item.key }} = {{ item.value }}"
  with_dict: my_default_values.update(my_values)

有没有办法合并两个字典,这样我就可以用“with_dict”来使用它?

6 个回答

2

试试这个来自Ansible Galaxy的角色

我之前也因为同样的原因用过这个。它可以把多个变量文件里的字典深度合并,并且可以设置合并的优先级。

这个角色可以在Ansible 2.0及以上版本中使用。

6

如果你需要多次使用合并后的字典,可以把它存储到一个新的“变量”里:

- set_fact: _my_values="{{ my_default_values|combine(my_values) }}"

- debug: msg="{{ item.key }} = {{ item.value }}"
  with_dict: _my_values
14

如果你想要合并哈希(也就是把多个变量合成一个),你需要在 Ansible 中开启这个功能。具体来说,在你的 Ansible 配置文件里,把哈希合并功能打开

当你设置 hash_behaviour=merge 后,你可以有两个变量文件,它们里面有相同的变量名:

第一个文件是 defaults.yml:

values:
  key: value

第二个文件是 overrides.yml:

values:
  my_key: my_value

为了让这两个变量合并,你需要同时包含这两个变量文件:

ansible-playbook some-play.yml ... -e@defaults.yml  -e@overrides.yml

这样你最终会得到:

TASK: [debug var=values] ********************************************************
ok: [localhost] => {
    "values": {
        "key": value,
        "my_key": my_value
    }
}

在 Jinja 中更新变量是可以做到的,但通常这样做会比较麻烦。我建议你不要在模板之外进行这样的操作,即使在模板中也尽量避免。

22

现在可以使用YAML的锚点和扩展功能了:

---
- hosts: localhost
  vars:
    my_default_values: &def
      key: value
    my_values:
      <<: *def
      my_key: my_value
  tasks:
    - debug: var=my_default_values
    - debug: var=my_values

结果:

TASK [debug]
ok: [localhost] => {
    "my_default_values": {
        "key": "value"
    }
}

TASK [debug] 
ok: [localhost] => {
    "my_values": {
        "key": "value", 
        "my_key": "my_value"
    }
}

我不知道为什么之前没有提到这个。

105

在 Ansible 2.0 中,有一个叫做 combine 的 Jinja 过滤器,可以用来做这个事情:

- debug: msg="{{ item.key }} = {{ item.value }}"
  with_dict: "{{ my_default_values | combine(my_values) }}"

撰写回答