Разница между поведением l oop и with_items с одним элементом и списком элементов - PullRequest
2 голосов
/ 12 июля 2020

При рассмотрении вопроса здесь возник другой вопрос.

Предположим, что переменная со списком dicts выглядит так:

some_var:
  - k: key1
    m: value1
  - k: key2
    m: value2
  - k: key3
    m: value3

Цикл по some_var с использованием кода ниже каждый элемент, как ожидалось.

- debug:
    msg: "{{ item }}"
  loop: "{{ some_var | flatten(1) }}"

Однако при размещении переменной l oop в виде списка, как показано ниже, она не l oop через отдельный элемент dict, а печатает весь список.

- debug:
    msg: "{{ item }}"
  loop: 
    - "{{ some_var | flatten(1) }}"

В чем причина этой разницы в поведении loop по сравнению с with_items, которое работает должным образом в обоих сценариях ios.

1 Ответ

2 голосов
/ 12 июля 2020

Различие в поведении, которое вы наблюдаете между with_items и loop, на самом деле связано с тем, как with_items сглаживает список для вас неявно, что делает это позже, чем когда вы сглаживаете его явно в своем loop, как рекомендовано в документации Ansible.

Итак, здесь разница просто проявляется в момент, когда список сглаживается:

  • Используя with_items, список сглаживается внутри Ansible, поэтому он будет эквивалентен:

    [ some_var ] | flatten(1)
    
  • When, в loop документации Ansible, как вы это видели , вы должны сгладить список самостоятельно, но, добавив список на один уровень выше, сглаживание произойдет слишком рано и, таким образом, будет эквивалентно:

    [ some_var | flatten(1) ]
    

Итак, если вы хотите точно и явно воспроизвести то же поведение, что и with_items в вашем l oop, вы должны сделать это:

- hosts: all
  gather_facts: no
  
  tasks:
    - debug:
        msg: "{{ item }}"
      loop: "{{ [ some_var | flatten(1) ] | flatten(1) }}"
      vars:
        some_var:
          - k: key1
            m: value1
          - k: key2
            m: value2
          - k: key3
            m: value3

Что работает, как и ожидалось:

PLAY [all] **********************************************************************************************************

TASK [debug] ********************************************************************************************************
ok: [localhost] => (item={'k': 'key1', 'm': 'value1'}) => {
    "msg": {
        "k": "key1",
        "m": "value1"
    }
}
ok: [localhost] => (item={'k': 'key2', 'm': 'value2'}) => {
    "msg": {
        "k": "key2",
        "m": "value2"
    }
}
ok: [localhost] => (item={'k': 'key3', 'm': 'value3'}) => {
    "msg": {
        "k": "key3",
        "m": "value3"
    }
}

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

Это потому, что вы создаете список списка во втором примере, в то время как l oop перебирает только первый уровень списка.

Итак, ваша первая рабочая книга эквивалентна цикл по переменной, отлаженной здесь:

- hosts: all
  gather_facts: no
  
  tasks:
    - debug:
        msg: "{{ some_var | flatten(1) }}"
      vars:
        some_var:
          - k: key1
            m: value1
          - k: key2
            m: value2
          - k: key3
            m: value3

Это дает:

PLAY [all] **********************************************************************************************************

TASK [debug] ********************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "k": "key1",
            "m": "value1"
        },
        {
            "k": "key2",
            "m": "value2"
        },
        {
            "k": "key3",
            "m": "value3"
        }
    ]
}

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

Ваш второй пример, однако, эквивалентен:

- hosts: all
  gather_facts: no
  
  tasks:
    - debug:
        msg: 
          - "{{ some_var | flatten(1) }}"
        ## Note that this above syntax is actually an equivalent to:
        # msg: "{{ [ some_var | flatten(1) ] }}"
      vars:
        some_var:
          - k: key1
            m: value1
          - k: key2
            m: value2
          - k: key3
            m: value3

Это дает:

PLAY [all] **********************************************************************************************************

TASK [debug] ********************************************************************************************************
ok: [localhost] => {
    "msg": [
        [
            {
                "k": "key1",
                "m": "value1"
            },
            {
                "k": "key2",
                "m": "value2"
            },
            {
                "k": "key3",
                "m": "value3"
            }
        ]
    ]
}

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

Видите, как у вас есть список списков во втором примере?

Итак, первый элемент первого примера - это

{'k': 'key1', 'm': 'value1'}

Как и следовало ожидать, а первый элемент второго - это просто список, содержащий все ваши элементы:

[   
    {
        "k": "key1",
        "m": "value1"
    },
    {
        "k": "key2",
        "m": "value2"
    },
    {
        "k": "key3",
        "m": "value3"
    }
]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...