json filter in creating a jinja2 template

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

json filter in creating a jinja2 template

问题

我正在尝试创建我的第一个 Jinja2 模板,从 JSON 字符串中提取一个字段,因为我正在创建 DHCP 预留文件。

以下是一个示例清单提供:

我想选择来自 MAC 地址的值,将其用作与 Ansible 主机匹配的接口字段的 Jinja2 值,该接口可以位于接口上的任何位置。

我应该如何操作


 "TEST": {
                "ansible_host": "192.171.130.8",
                "interfaces": [
                    {
                        "ip_addresses": [
                            {
                                "address": "192.171.130.8/32",
                            }
                        ],
                        "mac_address": "C8-F1-13-78-9E-E7"
                        
                    },
                    {
                        "ip_addresses": [
                            {
                                "address": "192.171.130.80/32",
                            }
                        ],
                        "mac_address": "85-9F-76-AE-57-10"
                        
                    }
                ],
                
               
         }

所以我想做类似以下的事情

{{ hostvars[host].interfaces.[ip_addresses.address = ansible_host].mac_address }}

但我不确定如何操作。

英文:

am trying to create my 1st jinja2 template that extracts a field from a json string as am trying to create DHCP reserveration file.

here is an example inventory feed.

I would like to select the value from the mac address to use as a value as jinja2 value for a field for the interface that matches the ansible host. which could be in any postion on the interfaces.

how would I go about it


 "TEST": {
                "ansible_host": "192.171.130.8",
                "interfaces": [
                    {
                        "ip_addresses": [
                            {
                                "address": "192.171.130.8/32",
                            }
                        ],
                        "mac_address": "C8-F1-13-78-9E-E7"
                        
                    },
                    {
                        "ip_addresses": [
                            {
                                "address": "192.171.130.80/32",
                            }
                        ],
                        "mac_address": "85-9F-76-AE-57-10"
                        
                    }
                ],
                
               
         }

so I would like to doe something like

{{ hostvars[host].interfaces.[ip_addresses.address = ansible_host].mac_address }}

but am not sure how to go about it.

答案1

得分: 2

这看起来是一个适合使用json_query过滤器的良好候选项。我的第一个想法是这应该可以工作:

hostvars[host].interfaces | json_query("[?ip_addresses[].address == '192.171.130.8/32']")

但这会返回一个空列表。以下代码有点冗长,但会产生预期的结果:

hostvars[host].interfaces | json_query("[?ip_addresses[].address | contains(@, '192.171.130.8/32')]")

在一个playbook中:

- hosts: localhost
  gather_facts: false
  vars:
    TEST:
      "ansible_host": "192.171.130.8",
      "interfaces": [
        {
          "ip_addresses": [
            {
              "address": "192.171.130.8/32"
            }
          ],
          "mac_address": "C8-F1-13-78-9E-E7"
        },
        {
          "ip_addresses": [
            {
              "address": "192.171.130.80/32"
            }
          ],
          "mac_address": "85-9F-76-AE-57-10"
        }
      ]
  tasks:
    - debug:
        msg: >
                    {{ TEST.interfaces | json_query("[?ip_addresses[].address | contains(@, '192.171.130.8/32')]") }}

注意:请注意引号的使用;在这里,我使用了YAML折叠引号操作符(>),因为表达式包含双引号和单引号,所以在表达式内部加上任何引号都需要转义。

运行上述playbook将产生以下结果:

ok: [localhost] => {
    "msg": [
        {
            "ip_addresses": [
                {
                    "address": "192.171.130.8/32"
                }
            ],
            "mac_address": "C8-F1-13-78-9E-E7"
        }
    ]
}

由于你已经将所需的地址存储在变量中(ansible_host),你可以改为写成:

  tasks:
    - debug:
        msg: >
          {{
            hostvars[host].interfaces | json_query("[?ip_addresses[].address | contains(@, '%s/32')]" % ansible_host)
          }}          

我们的表达式返回一个包含单个字典的列表。如果你想要mac_address字段,可以像处理任何其他Ansible数组变量一样处理结果:

  tasks:
    - debug:
        msg: >
          {{
          (
            hostvars[host].interfaces |
            json_query("[?ip_addresses[].address | contains(@, '%s/32')]" % ansible_host)
          )[0].mac_address
          }}          
英文:

This looks like a good candidate for the json_query filter. My first thought was that this should work:

hostvars[host].interfaces | json_query("[?ip_addresses[].address == '192.171.130.8/32']")

But that returns an empty list. The following is a bit more verbose, but produces the expected result:

hostvars[host].interfaces|json_query("[?ip_addresses[].address | contains(@, '192.171.130.8/32')]")

In a playbook:

- hosts: localhost
  gather_facts: false
  vars:
    TEST: {
      "ansible_host": "192.171.130.8",
      "interfaces": [
        {
          "ip_addresses": [
            {
              "address": "192.171.130.8/32",
              }
              ],
          "mac_address": "C8-F1-13-78-9E-E7"

          },
          {
            "ip_addresses": [
              {
                "address": "192.171.130.80/32",
                }
                ],
            "mac_address": "85-9F-76-AE-57-10"

            }
            ],


          }
  tasks:
    - debug:
        msg: >-
          {{ TEST.interfaces | json_query("[?ip_addresses[].address | contains(@, '192.171.130.8/32')]") }}

NB: Watch your quoting; you'll note that here I've used the YAML folding quote operating (>) because the expression contains both double quotes and single quotes, so putting either of those around the outside would mean escaping quotes inside the expression.

Running the above playbook produces:

ok: [localhost] => {
    "msg": [
        {
            "ip_addresses": [
                {
                    "address": "192.171.130.8/32"
                }
            ],
            "mac_address": "C8-F1-13-78-9E-E7"
        }
    ]
}

Since you've got the desired address in a variable (ansible_host), you would write instead:

  tasks:
    - debug:
        msg: >-
          {{
            hostvars[host].interfaces | json_query("[?ip_addresses[].address | contains(@, '%s/32')]" % ansible_host)
          }}

Our expression returns a list containing a single dictionary. If you want the mac_address field, treat the result just like any other Ansible array variable:

  tasks:
    - debug:
        msg: >-
          {{
          (
            hostvars[host].interfaces |
            json_query("[?ip_addresses[].address | contains(@, '%s/32')]" % ansible_host)
          ).0.mac_address
          }}

答案2

得分: 1

以下是代码部分的翻译:

  mac_ip_raw: "从MAC地址和IP列表创建字典"
  mac_ip_query: '[].[mac地址, IP地址[].地址]'
  mac_ip_raw:
    85-9F-76-AE-57-10:
    - 192.171.130.80/32
    C8-F1-13-78-9E-E7:
    - 192.171.130.8/32
  mac_ip: "去掉子网掩码"
  mac_ip:
    85-9F-76-AE-57-10:
    - 192.171.130.80
    C8-F1-13-78-9E-E7:
    - 192.171.130.8
  my_mac: "测试哪个列表包含IP"
  my_mac: C8-F1-13-78-9E-E7

希望这些翻译对你有所帮助。

英文:

Create the dictionary from the MAC addresses and lists of IPs

  mac_ip_raw: "{{ dict(interfaces|json_query(mac_ip_query)) }}"
  mac_ip_query: '[].[mac_address, ip_addresses[].address]'

gives

  mac_ip_raw:
    85-9F-76-AE-57-10:
    - 192.171.130.80/32
    C8-F1-13-78-9E-E7:
    - 192.171.130.8/32

Get rid of the masks

  mac_ip: "{{ dict(mac_ip_raw.keys()|
                   zip(mac_ip_raw.values()|
                       map('map', 'split', '/')|
                       map('map', 'first'))) }}"

gives

  mac_ip:
    85-9F-76-AE-57-10:
    - 192.171.130.80
    C8-F1-13-78-9E-E7:
    - 192.171.130.8

Now, test which list contains the IP

  my_mac: "{{ mac_ip|dict2items|
              selectattr('value', 'contains', ansible_host)|
              map(attribute='key')|first }}"

gives the expected result

  my_mac: C8-F1-13-78-9E-E7

<hr>
<sup>

Example of a complete project for testing

shell&gt; tree .
.
├── ansible.cfg
├── hosts
├── host_vars
│&#160;&#160; └── srv1
│&#160;&#160;     └── interfaces.json
└── pb.yml

2 directories, 4 files
shell&gt; cat ansible.cfg 
[defaults]
gathering = explicit
collections_path = $HOME/.local/lib/python3.9/site-packages/
inventory = $PWD/hosts
roles_path = $PWD/roles
retry_files_enabled = false
stdout_callback = yaml
shell&gt; cat hosts
srv1 ansible_host=192.171.130.8
shell&gt; cat host_vars/srv1/interfaces.json 
{
  &quot;interfaces&quot;:
    [
        {
            &quot;ip_addresses&quot;: [
                {
                    &quot;address&quot;: &quot;192.171.130.8/32&quot;
                }
            ],
            &quot;mac_address&quot;: &quot;C8-F1-13-78-9E-E7&quot;
        },
        {
            &quot;ip_addresses&quot;: [
                {
                    &quot;address&quot;: &quot;192.171.130.80/32&quot;
                }
            ],
            &quot;mac_address&quot;: &quot;85-9F-76-AE-57-10&quot;
        }
    ]
}
shell&gt; cat pb.yml 
- hosts: all

  vars:

    mac_ip_raw: &quot;{{ dict(interfaces|json_query(mac_ip_query)) }}&quot;
    mac_ip_query: &#39;[].[mac_address, ip_addresses[].address]&#39;
    mac_ip: &quot;{{ dict(mac_ip_raw.keys()|
                     zip(mac_ip_raw.values()|
                         map(&#39;map&#39;, &#39;split&#39;, &#39;/&#39;)|
                         map(&#39;map&#39;, &#39;first&#39;))) }}&quot;
    my_mac: &quot;{{ mac_ip|dict2items|
                selectattr(&#39;value&#39;, &#39;contains&#39;, ansible_host)|
                map(attribute=&#39;key&#39;)|first }}&quot;
    
  tasks:

    - debug:
        var: ansible_host
    - debug:
        var: interfaces
    - debug:
        var: mac_ip_raw
    - debug:
        var: mac_ip
    - debug:
        var: my_mac

</sup>

huangapple
  • 本文由 发表于 2023年3月4日 03:18:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/75631071.html
匿名

发表评论

匿名网友

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

确定