json 变量的 Ansible 过滤器

Ansible filter for json variable

一些背景信息。我正在使用 netbox 作为我们网络自动化的真实来源,我目前正在做一些测试以自动化瞻博网络配置。 Netbox 目前用作我的 ansible 库存并提供 host_vars.

我想完成一个简单的任务,即根据主机变量在我的 Juniper 配置中设置一个“值”。

问题

我最明确地使用了错误的 map/filter 组合来实现循环遍历字典“dns”中的值的目标,但我已经尝试了无数次但没有任何成功,所以将我的问题提交给社区征求意见。

我有以下 host_vars:

{
  "ansible_host": "192.168.1.1",
  "config_context": [
    {
      "_utility": {
        "dns": [
          "10.10.10.10",
          "10.10.10.20"
        ]
      }
    }
  ],
  "device_roles": [
    "leaf"
  ],
  "device_types": [
    "qfx5120-48y"
  ]
}

我的任务目前看起来像:

- name: Set DNS server
  juniper.device.config:
    config_mode: 'exclusive'
    load: 'set'
    lines:
      - 'set system name-server "{{ item }}"'
  loop: "{{ config_context | map(attribute='_utility') | flatten | map(attribute='dns') | flatten }}"

发出错误信息

尝试调试它注册一个变量并使用调试消息打印它:

调试

- name: Print var
  vars:
    - nameservers: "{{ config_context | map(attribute='_utility') | flatten | map(attribute='dns') | flatten }}"
  debug:
    msg:
      - "{{ nameservers }}"

结果

ok: [poc-spine01-re] => {
    "msg": [
        [
            "10.10.10.10",
            "10.10.10.20"
        ]
    ]
}

但是,当尝试使用结果循环遍历值时,我得到另一个错误

调试

- name: Print var loop
  vars:
    - nameservers: "{{ config_context | map(attribute='_utility') | flatten | map(attribute='dns') | flatten }}"
  debug:
    msg:
      - "{{ item }}"
  loop: nameservers

结果

fatal: [poc-leaf03-re]: FAILED! => {
    "msg": "Invalid data passed to 'loop', it requires a list, got this instead: nameservers. Hint: If you passed a list/dict of just one element, try adding wantlist=True to your lookup invocation or use q/query instead of lookup."
}
fatal: [poc-spine01-re]: FAILED! => {
    "msg": "Invalid data passed to 'loop', it requires a list, got this instead: nameservers. Hint: If you passed a list/dict of just one element, try adding wantlist=True to your lookup invocation or use q/query instead of lookup."
}

更新

嗨,它适用于循环!。我已经调整了我的变量,现在正在考虑是否应该只获取密钥 dns1 或 dns2 的值(不在循环中)

主机变量

{
  "ansible_host": "192.168.1.1",
  "config_context": [
    {
      "_utility": {
        "dns": {
          "dns1": "10.10.10.10",
          "dns2": "10.10.10.20"
        }
      }
    }
  ],
  "device_roles": [
    "leaf"
  ],
  "device_types": [
    "qfx5120-48y"
  ]
}

但无法让地图过滤器正确显示一个值

任务

- name: Set DNS server
  vars:
    ns1: "{{ config_context | map(attribute='_utility.dns.dns1') | flatten }}"
  juniper.device.config:
    config_mode: 'exclusive'
    load: 'set'
    lines:
      - 'set system name-server "{{ ns1 }}"'

结果

如您所见,10.10.10.10 的值用方括号和双引号引起来,而不仅仅是 10.10.10.10

的值字符串
fatal: [poc-spine01-re]: FAILED! => {
    "changed": false,
    "invocation": {
        "module_args": {
            "lines": [
                "set system name-server \"['10.10.10.10']\""
            ],

你的循环应该修复如下:

    loop: "{{ config_context | map(attribute='_utility.dns') | flatten }}"

此外,我会添加一些额外的过滤器以确保:

  • 如果在多个 config_context 条目(即 unique)中声明同一个 dns,则您不会循环两次
  • 你总是以相同的顺序去其他列表(即 sort
    loop: "{{ config_context | map(attribute='_utility.dns') | flatten | unique | sort }}"

旁注

- name: Print var loop
  vars:
    - nameservers: "{{ config_context | map(attribute='_utility') | flatten | map(attribute='dns') | flatten }}"
  debug:
    msg:
      - "{{ item }}"
  loop: nameservers

这个任务中的三个问题。

  1. 虽然它实际上与列表“一起工作”(ansible 会自动转换),但您的 vars 声明应该是一个映射:
    vars:
      nameservers: "{{ config_context | map(attribute='_utility') | flatten | map(attribute='dns') | flatten }}"
    
  2. 您正在遍历 字符串 "nameservers"。您想要遍历具有该名称的变量的内容:
    loop: "{{ nameservers }}"
    
  3. 在您的调试消息中,您要求打印一个列表,其中第一个元素内容是 item 变量中的任何值。您真正想要的是直接打印该变量的内容,这可以通过
    debug:
      msg: "{{ item }}"
    
    或者因为您没有通过直接寻址 var 对内容进行任何处理
    debug:
      var: item
    

把它们放在一起并整合我上面的修复,这是你问题的核心:

- name: Print var loop
  vars:
    nameservers: "{{ config_context | map(attribute='_utility.dns') | flatten | unique | sort }}"
  debug:
    var: item
  loop: "{{ nameservers }}"