【问题标题】:merging dictionaries in ansible在ansible中合并字典
【发布时间】:2014-10-14 21:02:20
【问题描述】:

我目前正在构建一个使用 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”一起使用?

【问题讨论】:

标签: python dictionary merge ansible


【解决方案1】:
>>> key = 'default key'
>>> value = 'default value'
>>> my_key = 'my key'
>>> my_value = 'my value'
>>>
>>> my_default_values = {key: value}
>>> print my_default_values
{'default key': 'default value'}
>>>
>>> my_values = {my_key: my_value}
>>> print my_values
{'my key': 'my value'}
>>>
>>> with_dict = my_default_value.copy()
>>> print with_dict
{'default key': 'default value'}
>>> with_dict.update(my_values)
>>> print with_dict
{'default key': 'default value', 'my key': 'my value'}

【讨论】:

  • 对,这就是我在上一个示例中使用的。这在 ansible 中不起作用,或者看起来是这样。
【解决方案2】:

如果你想要哈希合并,我会在 ansible 中打开哈希合并功能。 在你的 ansible 配置文件 turn hash merging on.

使用 hash_behaviour=merge,您可以拥有两个具有相同变量名的 var 文件:

defaults.yml:

values:
  key: value

overrides.yml:

values:
  my_key: my_value

为了合并两个 var,您需要包含两个 var 文件:

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 中对变量调用更新,但通常会很麻烦,我不会在您的模板之外执行此操作,甚至尝试完全避免它。

【讨论】:

  • 更改此设置可能会破坏其他角色。试试 jinja2 combine 方法。
  • 遵循@kalu 所说的 - 不鼓励使用哈希合并是危险的。
【解决方案3】:

在 Ansible 2.0 中,有一个 Jinja 过滤器,combine,用于此:

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

【讨论】:

【解决方案4】:

如果你需要合并字典几次,你可以将它设置为一个新的“变量”:

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

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

【讨论】:

    【解决方案5】:

    试试 Ansible Galaxy 的 this role

    我前段时间出于同样的原因这样做了。它可以从多个 vars 文件中深度合并字典并设置自定义合并优先级。

    这个角色可以在 Ansible 2.0+ 下工作

    【讨论】:

      【解决方案6】:

      现在可以使用 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"
          }
      }
      

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

      【讨论】:

      • 太酷了!虽然这可以完成任务,但我认为问题在于您需要使用“&name”来装饰所有源对象,这可能过于繁琐。如果您使用共享角色,其中角色(和原始变量对象)由其他人维护,这可能是一个问题。另外,我还没有测试过它,但它似乎可能存在运行时问题,评估发生在文件加载时,Jinja 模板解决方案可能在预期时间发生,特别是如果有“何时”修饰符.关于 this 和 combine() 之间的评估时间有什么想法吗?
      猜你喜欢
      • 2020-12-28
      • 2022-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-14
      • 1970-01-01
      • 1970-01-01
      • 2017-08-03
      相关资源
      最近更新 更多