【问题标题】:ansible template fail if dictionary is empty如果字典为空,ansible 模板会失败
【发布时间】:2021-11-01 04:32:59
【问题描述】:

我在 ansible 模板中有以下内容。

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

http_requests 通常在 playbook 中定义如下:

   http_requests:
      - randomhttprequest

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

即使像这样将 http_requests 列表留空,我也正在努力寻找使剧本失败的方法

   http_requests:
      -
      -

我尝试过使用长度而不是无,但我似乎无法让它发挥作用。

【问题讨论】:

  • 我不认为这是一个空变量,而是一个包含两个空字符串的列表。
  • 抱歉,你是对的,我刚开始学习这些东西。问题仍然是一个空列表
  • 如果列表为空,您是否要故意使 playbook 失败?
  • @RafadeBoas 是的
  • @user3925030 在您的“空”列表示例中,该列表实际上不是空的。它由两个空列表组成……换句话说:http_requests = [[], []]

标签: python ansible jinja2


【解决方案1】:

问:在列表为空的情况下故意使剧本失败。

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

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

为了检查列表的所有子项是否为“空”(如 [[]、[]、...]),您可以使用 Ansible 函数 map、length、总和。例如

- 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

【讨论】:

  • 我问提问者是否故意让剧本失败,以防列表为空,所以这不能回答他们的问题
  • 谢谢。这澄清了这个案子。我更新了答案。
  • 我相信提问者正在寻找如何检查列表列表是否为空(因为他们的“空列表”示例)。在这里使用长度是不够的(请参阅下面的答案)
  • 当然。我已经做了。并更新了这个案例的答案。谢谢。
  • 非常漂亮,非常优雅!
【解决方案2】:

为了检查列表的所有子项是否为“空”(如[[], [], ...]),您可以使用一些 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"

毫无疑问,这非常丑陋。但是,它完成了工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-26
    • 2016-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多