如果dictionary为空, ansible模板失败



我在一个可见的模板中有以下内容:

{% if value.http_requests is defined %}
{% for http_request in value.http_requests %}
http-request    {{ http_request }}
{% endfor %}
{% endif %}

http_requests通常在脚本中定义如下:

http_requests:
- randomhttprequest

如果变量已定义,但列表为空,则模板将显示没有值的http-request。

我正在努力寻找一种方法来失败的剧本,即使http_requests列表是空的,像这样

http_requests:
-
-

我试过使用长度而不是none,但我似乎不能使它工作。

Q:">在列表为空的情况下故意使剧本失败">

A:关于如何测试它并优雅地失败有很多选择。例如,您可能希望使用assert

- assert:
that: value.http_requests|default([])|length == 0
fail_msg: Error. Tne list value.http_requests is empty.

为了检查列表的所有子元素是否都为"空";(如[[],[],…])可以使用Ansible函数map, length,sum。例如

- hosts: localhost
vars:
http_requests1:
- randomhttprequest
- ""
http_requests2:
- ""
- ""
tasks:
- name: Sanity http_requests1
assert:
that: http_requests1|map('length')|sum > 0
fail_msg: Error. All items of the list http_requests are empty.
- name: Sanity http_requests2
assert:
that: http_requests2|map('length')|sum > 0
fail_msg: Error. All items of the list http_requests are empty.

ok: [localhost] => changed=false 
msg: All assertions passed
fatal: [localhost]: FAILED! => changed=false 
assertion: http_requests2|map('length')|sum > 0
evaluated_to: false
msg: Error. All items of the list http_requests are empty.

为了避免模板中的undefined variable错误,使用过滤器default,例如

{% for http_request in value.http_requests|default([]) %}
http-request    {{ http_request }}
{% endfor %}

如果你只想迭代非空字符串,也要测试循环中的长度,例如

- name: Iterate only non-empty strings
debug:
msg: |
{% for http_request in http_requests1|default([]) %}
{% if http_request|length > 0 %}
http-request    {{ http_request }}
{% endif %}
{% endfor %}

msg: |-
http-request    randomhttprequest

为了检查列表的所有子元素是否都为"空";(如[[], [], ...])您可以使用一些Python内置:

# This will return True
example_list = [[], []]
empty = all(not l for l in map(lambda l: bool(l), example_list))
# This will return False
example_list = [[1, 2], []]
empty = all(not l for l in map(lambda l: bool(l), example_list))

我建立了一个示例剧本,它完全是这样做的:

- name: Check for empty list example
hosts: localhost
connection: local
vars:
example_list:
-
-
tasks:
# Calling Python here is necessary because Jinja2 doesn't have 
# an `all()` filter, so I had to improvise. 
- name: check for empty list
register: result
args: 
stdin: |
print(all(not l for l in map(lambda l: bool(l), {{ example_list }})))
command: python
- debug:
msg: 'list is empty'
# String comparison because we're `print()`ing the result
# of the Python expression...
when: result.stdout == "True"
- name: lets fail
debug:
msg: 'list is not empty'
failed_when: result.stdout == "True"
毫无疑问,这是非常丑陋的。然而,它完成了工作。

最新更新