返回更新后的未排序字典在Ansible中。

huangapple go评论88阅读模式
英文:

Return updated unsorted dict in Ansible

问题

我正在尝试合并一些字典,并保留它们各自位置上的项目,就像在Python中使用dict.update()一样工作,但在Ansible中遇到了一些问题。

例如,我有两个字典:

dict1:
  c_value: None

dict2:
  b_value: None
  a_value: None

我想要合并它们并保留顺序:

dict3:
  c_value: None
  b_value: None
  a_value: None

我尝试了两种解决方案,使用Jinja2和Ansible过滤器combine。它们在Jinja2在线编辑器中都正常工作,但如果我在Ansible中使用它们 - 调试显示我已按键名排序了字典:

dict3:
  a_value: None
  b_value: None
  c_value: None

Jinja2模板:{%-set _ = dict1.update(dict2) -%}{{- dict1 -}}

Ansible combine:dict1 | combine(dict2)

英文:

I am trying to merge some dicts with saving their items on their own places like it is working in python using dict.update(), but i have some troubles with it in Ansible.

For example, I have two dicts:

dict1:
  c_value: None

dict2:
  b_value: None
  a_value: None

I want to merge them with saving order:

dict3:
  c_value: None
  b_value: None
  a_value: None

I have tried 2 solutions, using jinja2 and ansible filter combine. All of them works fine in jinja2 online editors, but if i use it in ansible - debugging shows that I have sorted dict by key name:

dict3:
  a_value: None
  b_value: None
  c_value: None

Jinja2 template: {%-set _ = dict1.update(dict2) -%}{{- dict1 -}}

Ansible combine: dict1 | combine(dict2)

答案1

得分: 1

以下是翻译好的部分:

字典,又称为 映射,在 YAML 中定义如下:

> "一个无序的键/值节点对的集合,..."

换句话说,在 YAML 中,字典的键没有固定的顺序。你看到的可能是 Python 3.7+ 的行为:

> "现在字典按照变量定义的词法顺序显示。之前,顺序是未定义的。"

查看 Ansible 使用的 Python 版本(在控制节点上执行):

shell> ansible --version
ansible [core 2.14.3]
  ...
  python version = 3.9.17 (main, Jun  6 2023, 20:11:04) [GCC 9.4.0] (/usr/bin/python3.9)
  jinja version = 3.1.2
  libyaml = True

给定以下字典:

  dict1:
    c_value: None
  dict2:
    b_value: None
    a_value: None

将它们合并:

  dict3: "{{ dict1|combine(dict2) }}"
  • 在 Python 3.7+ 中,键按词法顺序排序:
    - debug:
        msg: |
                    {{ dict3 }}

输出:

  msg:
    a_value: None
    b_value: None
    c_value: None
  • 如果你想要其他顺序的键,可以这样声明。例如:
    - debug:
        msg: |
          {% for k in key_order %}
          {{ k }}: {{ dict3[k] }}
          {% endfor %}          
      vars:
        key_order: [c_value, b_value, a_value]

输出:

  msg: |- 
    c_value: None
    b_value: None
    a_value: None
  • 但是,如果你将文本转换为 YAML,则会再次得到排序后的键:
    - debug:
        msg: |
          {% filter from_yaml %}
          {% for k in key_order %}
          {{ k }}: {{ dict3[k] }}
          {% endfor %}
          {% endfilter %}          
      vars:
        key_order: [c_value, b_value, a_value]

输出:

  msg:
    a_value: None
    b_value: None
    c_value: None

<hr>

<sup>

用于测试的完整 playbook 示例:

- hosts: localhost

  vars:

    dict1:
      c_value: None
    dict2:
      b_value: None
      a_value: None

    dict3: &quot;{{ dict1|combine(dict2) }}&quot;

  tasks:

    - debug:
        msg: |
                    {{ dict3 }}

    - debug:
        msg: |
          {% for k in key_order %}
          {{ k }}: {{ dict3[k] }}
          {% endfor %}          
      vars:
        key_order: [c_value, b_value, a_value]

    - debug:
        msg: |
          {% filter from_yaml %}
          {% for k in key_order %}
          {{ k }}: {{ dict3[k] }}
          {% endfor %}
          {% endfilter %}          
      vars:
        key_order: [c_value, b_value, a_value]
英文:

A dictionary aka mapping is:

> "an unordered set of key/value node pairs, ..."

In other words, in YAML, there is no order in the dictionary's keys. What you see is probably Python 3.7+:

> "A dictionary now displays in the lexical order that variables were defined. Previously, the order was undefined."

See what Python your version of Ansible uses (on the controller)

shell&gt; ansible --version
ansible [core 2.14.3]
  ...
  python version = 3.9.17 (main, Jun  6 2023, 20:11:04) [GCC 9.4.0] (/usr/bin/python3.9)
  jinja version = 3.1.2
  libyaml = True

Given the dictionaries

  dict1:
    c_value: None
  dict2:
    b_value: None
    a_value: None

combine them

  dict3: &quot;{{ dict1|combine(dict2) }}&quot;
  • The keys are ordered lexicographically by Python 3.7+
    - debug:
        msg: |
                    {{ dict3 }}

gives

  msg:
    a_value: None
    b_value: None
    c_value: None
  • You have to declare another order of keys if you want to. For example,
    - debug:
        msg: |
          {% for k in key_order %}
          {{ k }}: {{ dict3[k] }}
          {% endfor %}          
      vars:
        key_order: [c_value, b_value, a_value]

gives

  msg: |-
    c_value: None
    b_value: None
    a_value: None    
  • But, if you convert the text to YAML you get the ordered keys again
    - debug:
        msg: |
          {% filter from_yaml %}
          {% for k in key_order %}
          {{ k }}: {{ dict3[k] }}
          {% endfor %}
          {% endfilter %}          
      vars:
        key_order: [c_value, b_value, a_value]

gives

  msg:
    a_value: None
    b_value: None
    c_value: None

<hr>

<sup>

Example of a complete playbook for testing

- hosts: localhost

  vars:

    dict1:
      c_value: None
    dict2:
      b_value: None
      a_value: None

    dict3: &quot;{{ dict1|combine(dict2) }}&quot;

  tasks:

    - debug:
        msg: |
                    {{ dict3 }}

    - debug:
        msg: |
          {% for k in key_order %}
          {{ k }}: {{ dict3[k] }}
          {% endfor %}          
      vars:
        key_order: [c_value, b_value, a_value]

    - debug:
        msg: |
          {% filter from_yaml %}
          {% for k in key_order %}
          {{ k }}: {{ dict3[k] }}
          {% endfor %}
          {% endfilter %}          
      vars:
        key_order: [c_value, b_value, a_value]

</sup>

huangapple
  • 本文由 发表于 2023年7月24日 18:56:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76753782.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定