сбой шаблона ansible, если словарь пуст

#python #ansible #jinja2

Вопрос:

У меня есть следующее в шаблоне 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-запрос без значения.

Я изо всех сил пытаюсь найти способ провалить учебник, даже если список http_requests остается пустым, как это

    http_requests:
      -
      -
 

Я пробовал использовать длину, а не ничего, но, похоже, я не могу заставить это работать.

Комментарии:

1. Я не думаю, что это пустая переменная, а скорее список с двумя пустыми строками.

2. извините, что вы правы, я новичок в изучении этих вещей. вопрос все еще остается с пустым списком

3. вы хотите специально провалить учебник в том случае, если список пуст?

4. @RafadeBoas да

5. @user3925030 в вашем примере с «пустым» списком список на самом деле не пустой. он состоит из двух пустых списков… другими словами: http_requests = [[], []] .

Ответ №1:

Вопрос: «Намеренно провалите учебник в случае, если список был пуст».

Ответ: Есть много вариантов того, как протестировать его и изящно провалиться. Например, вы можете использовать assert

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

Чтобы проверить, являются ли все дочерние элементы списка «пустыми» (как в [[], [], …]) вы можете использовать расширяемые функции 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 ошибок в шаблоне, используйте фильтр по умолчанию, например

 {% 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
 

Комментарии:

1. я спросил спрашивающего, хотели ли они намеренно провалить учебник в случае, если список был пуст, чтобы это не решило их проблему

2. Спасибо. Это прояснило дело. Я обновил ответ.

3. я считаю, что спрашивающий ищет способ проверить, является ли список списков пустым (из-за их примера «пустой список»). использование длины здесь было бы недостаточно (см. Мой ответ ниже)

4. Конечно. Я уже сделал это. И обновил ответ и по этому делу. Спасибо.

5. Очень красиво и очень элегантно!

Ответ №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"
 

Это, без сомнения, очень некрасиво. Тем не менее, он выполняет свою работу.