【问题标题】:Ansible Loop Get Next ValueAnsible 循环获取下一个值
【发布时间】:2020-02-28 11:59:57
【问题描述】:

我目前在循环执行特定任务时遇到了一些麻烦。 首先,我需要循环特定的结构:

companies:
  - name: Facebook
    company_url: "https://www.facebook.com"
    company_certificate: "Facebook.crt"
    port_type: "AS2"
    create_filematch: "yes"
    filters:
        - name: "ORDERS"
          regex: "ORDER*"
        - name: "INVOICES"
          regex: "INVOICE*"
  - name: Google
    company_url: "https://www.google.com"
    company_certificate: "Google.crt"
    port_type: "AS2"
    create_filematch: "yes"
    filters:
        - name: "ORDERS"
          regex: "ORDER*"
        - name: "INVOICES"
          regex: "INVOICE*"

我需要循环“过滤器”的子元素。我正在使用以下循环:

loop: "{{ companies | subelements('filters', skip_missing=True) }}"

问题是我需要在模板中填写两个字段:ma​​tchelsema​​tch 字段应该是循环的当前项。第二个字段应该是下一项。

例如,如果我有这个子元素结构: 子元素: sub1:值 sub2:值 sub3: 值

然后我在这些子元素上使用循环,我的模板中的两个字段应该如下所示:

match_send=sub1
else_send=sub2

然后是下一项

match_send=sub2
else_send=sub3

我该怎么做?

谢谢。

【问题讨论】:

  • 我不确定我是否理解:您谈论的是模板,所以您希望能够将您的子元素列表用作模板的数据输入?
  • 是的,我想使用子元素来填充我的模板。问题是我知道如何用我正在循环的当前项目填充模板,但是在我的模板中的某个时刻我需要获取循环的下一个项目的值。
  • 好吧,我认为你不能那样做。如果它是一个要渲染的大模板,那么您可以传递整个列表并在模板中使用 loop.nextitem。但是当你使用循环时,渲染任务一次只接收一个元素。
  • 是的,这就是我的恐惧^^。我发现的唯一解决方案是有一个包含下一个子元素名称的子元素。但在我看来,这是一个丑陋的解决方案

标签: ansible yaml


【解决方案1】:

问:“match and else。匹配字段应该是循环的当前项。第二个字段应该是下一项。”

答:Extended loop variables 服务于这个目的。例如

- hosts: localhost
  vars:
    companies:
      - name: 'Amazon'
        filters:
          - 'filter-A1'
          - 'filter-A2'
          - 'filter-A3'
      - name: 'Facebook'
        filters:
          - 'filter-F1'
          - 'filter-F2'
          - 'filter-F3'
      - name: 'Google'
        filters:
          - 'filter-G1'
          - 'filter-G2'
          - 'filter-G3'

  tasks:

    - debug:
        msg:
          - "match: {{ item.0.name }} -
                    {{ item.1 }}"
          - "else: {{ ansible_loop.nextitem.0.name|default('last item') }} -
                   {{ ansible_loop.nextitem.1|default('last subitem') }}"
      loop: "{{ companies|subelements('filters', skip_missing=True) }}"
      loop_control:
        extended: true

给予

    "msg": [
        "match: Amazon - filter-A1", 
        "else: Amazon - filter-A2"
    ]
--
    "msg": [
        "match: Amazon - filter-A2", 
        "else: Amazon - filter-A3"
    ]
--
    "msg": [
        "match: Amazon - filter-A3", 
        "else: Facebook - filter-F1"
    ]
--
    "msg": [
        "match: Facebook - filter-F1", 
        "else: Facebook - filter-F2"
    ]
--
    "msg": [
        "match: Facebook - filter-F2", 
        "else: Facebook - filter-F3"
    ]
--
    "msg": [
        "match: Facebook - filter-F3", 
        "else: Google - filter-G1"
    ]
--
    "msg": [
        "match: Google - filter-G1", 
        "else: Google - filter-G2"
    ]
--
    "msg": [
        "match: Google - filter-G2", 
        "else: Google - filter-G3"
    ]
--
    "msg": [
        "match: Google - filter-G3", 
        "else: last item - last subitem"
    ]

问:“我希望它表现得像这样:”

 "msg": [ "match: Facebook - filter-F2",
          "else: Facebook - filter-F3" ]
 "msg": [ "match: Facebook - filter-F3",
          "else: " ]

“例如,当到达 Facebook 的最后一个子项时,next_item 的值应该为空。”

答:试试这个

    - debug:
        msg: "{{ msg.split('\n') }}"
      vars:
        msg: |
          - match: {{ item.0.name }} -  {{ item.1 }}
          {% if item.0.name == ansible_loop.nextitem.0.name|default('last item') %}
          - else: {{ ansible_loop.nextitem.0.name }} -  {{ ansible_loop.nextitem.1 }}
          {% else %}
          - else: ''
          {% endif %}
      loop: "{{ companies|subelements('filters', skip_missing=True) }}"
      loop_control:
        label: "{{ item.0.name }}"
        extended: true

最后,如果你想用这个列表创建一个变量,试试

    - set_fact:
        companies1: "{{ companies1|default([]) + [company|from_yaml] }}"
      vars:
        company: |
          [{match: '{{ item.0.name }} - {{ item.1 }}'},
          {%- if item.0.name == ansible_loop.nextitem.0.name|default('last item') %}
          {else: '{{ ansible_loop.nextitem.0.name }} -  {{ ansible_loop.nextitem.1 }}'}]
          {%- else %}
          {else: ''}]
          {% endif %}
      loop: "{{ companies|subelements('filters', skip_missing=True) }}"
      loop_control:
        label: "{{ item.0.name }}"
        extended: true
    - debug:
        msg: "{{ msg.split('\n') }}"
      vars:
        msg: "{{ companies1|to_yaml }}"

    "msg": [
        "- - {match: Amazon - filter-A1}", 
        "  - {else: Amazon -  filter-A2}", 
        "- - {match: Amazon - filter-A2}", 
        "  - {else: Amazon -  filter-A3}", 
        "- - {match: Amazon - filter-A3}", 
        "  - {else: ''}", 
        "- - {match: Facebook - filter-F1}", 
        "  - {else: Facebook -  filter-F2}", 
        "- - {match: Facebook - filter-F2}", 
        "  - {else: Facebook -  filter-F3}", 
        "- - {match: Facebook - filter-F3}", 
        "  - {else: ''}", 
        "- - {match: Google - filter-G1}", 
        "  - {else: Google -  filter-G2}", 
        "- - {match: Google - filter-G2}", 
        "  - {else: Google -  filter-G3}", 
        "- - {match: Google - filter-G3}", 
        "  - {else: ''}", 
        ""
    ]

【讨论】:

  • 感谢您的回答,这就是我想要的。我仍然有一个问题,如果我到达最后一个子项目,next_item 不会为空,但它会拾取循环的第一个项目。如果您对如何停止这种行为有想法:)
  • 你想让所有子项的行为都像 filter-Gx 那样吗?
  • 是的,但是当我到达子元素列表的最后一项时, ansible_loop.nextitem 会采用我列表中第一项的值。 :(
  • 你能重现我的例子吗?
  • 是的。我知道现在发生了什么。我误解了 next_item 参数。我只想要所选项目的 next_item 。如果你举个例子,我希望它表现得像这样:“msg”:[“match:Facebook - filter-F2”,“else:Facebook - filter-F3”] - “msg”:[“match:Facebook - filter-F3", "else: " ] 所以当它到达 Facebook 的最后一个 subitem 时,next_item 的值应该是空的。
【解决方案2】:

尽管我的 cmets 我认为我找到了解决方案。 您也许可以使用 with_together。

我想出了一个可行的例子:

---
- hosts: localhost
  vars:
  - list1:
    - a
    - b
    - c
  tasks:
  - name: with_together
    debug:
      msg: "{{ item.0 }} - {{ item.1 }}"
    with_together:
      - "{{ list1 }}"
      - "{{ list1[1:] }}"

给出:

TASK [with_together] ************************************************************************************************************************************************
ok: [localhost] => (item=[u'a', u'b']) => {
    "msg": "a - b"
}
ok: [localhost] => (item=[u'b', u'c']) => {
    "msg": "b - c"
}
ok: [localhost] => (item=[u'c', None]) => {
    "msg": "c - "
}

我相信您可以根据您的用例对其进行调整。

【讨论】:

    猜你喜欢
    • 2011-12-04
    • 2019-12-21
    • 1970-01-01
    • 1970-01-01
    • 2022-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-25
    相关资源
    最近更新 更多