Ansible 过滤器 return 可以未定义吗?

Can an Ansible filter return Undefined?

我正在编写一个 Ansible 过滤器。有没有可能这个filter returns Undefined,所以结果输出是Undefined?

我的目标是在以下情况下可以将过滤器与 defaultselect 结合使用:

my_variable: "{{ my_input | myfilter | default(something) }}"

或:

my_list: "{{ list_of_things | map('myfilter') | select | list }}"

例如:

- vars:
    area: 9
    side: "{{ area | my_sqrt | default(0) }}"
  debug:
    var: side

或:

- vars:
    numbers: [16, 9, -4]
    roots: "{{ numbers | map('my_sqrt') | select | list }}"
  debug:
    var: roots

其中 map('my_sqrt') 应该输出 [4, 3, Undefined]select 应该把它变成 [4, 3].

我试图将 my_sqrt 定义为:

import math
from jinja2.runtime import Undefined

def my_sqrt(input):
    if input < 0:
        return Undefined
    else:
        return math.sqrt(input)

class FilterModule(object):
    def filters(self):
        return { 'my_sqrt': my_sqrt }

但是,当我执行上面的剧本时,似乎 return 字符串 <class 'jinja2.runtime.Undefined'>.

一些进一步的测试证明了这一点:

('never' if 0) | default('the_default')确实returns the_default.

然而,-4 | my_sqrt | default('the_default') 可悲的是 return 字符串 "<class 'jinja2.runtime.Undefined'>"

我都尝试过 jinja2.runtime.Undefinedansible.template.AnsibleUndefined

我主要想知道 Ansible/Jinja2 过滤器是否可以 return Undefined.

如果那不可能,我很想听听其他方法。我实际上正在写的是一个过滤器,它接受一个对象和一个选项列表(可能的匹配),并将 return 最佳选项(最佳匹配)。如果没有好的选项,应该returnUndefined,之后就看剧本怎么处理了。作为基本要求,它应该适用于 defaultselect.

您可以将 filter 定义为 return None 而不是 Undefined。然后,您可以将输出通过管道传输到 selectdefault 过滤器,但需要注意。

None 将被 default 过滤器解释为布尔值。因此,您必须将值 true 作为 default 过滤器的第二个参数传递,它才能按预期工作。

使用此代码试试:

过滤器定义:

#!/bin/bash

import math
import typing as t

V = t.TypeVar("V")

def my_sqrt(value: V) -> t.Union[V , None]:
    if value < 0:
        return None
    else:
        return math.sqrt(value)

class FilterModule(object):
    def filters(self):
        return {
            'my_sqrt': my_sqrt
        }

剧本示例:

- hosts: localhost
  gather_facts: no
  tasks:
    - name: Test the my_sqrt filter
      debug:
        msg: "{{ item | my_sqrt | default(0, true) }}"
      loop:
        - 4
        - -1

    - name: Select
      debug:
        msg: "{{ [4, 3, -4] | map('my_sqrt') | select | list }}"

您会看到 tasks 都按预期工作:


PLAY [localhost] ***************************************************************
Friday 14 May 2021  09:27:41 -0300 (0:00:00.019)       0:00:00.019 ************ 

TASK [Test the my_sqrt filter] *************************************************
ok: [localhost] => (item=4) => 
  msg: '2.0'
ok: [localhost] => (item=-1) => 
  msg: '0'
Friday 14 May 2021  09:27:41 -0300 (0:00:00.042)       0:00:00.062 ************ 

TASK [Select] ******************************************************************
ok: [localhost] => 
  msg:
  - 2.0
  - 1.7320508075688772

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Friday 14 May 2021  09:27:41 -0300 (0:00:00.044)       0:00:00.106 ************ 
=============================================================================== 
Select ------------------------------------------------------------------ 0.04s
Test the my_sqrt filter ------------------------------------------------- 0.04s