首页 > 解决方案 > Ansible 嵌套循环和条件一起在同一个任务中

问题描述

---

    - hosts: leaf-1, leaf-2
      vars_files:
        - /vars/all.yml

      tasks:
      - name: collect the vlan databse
        raw: "show vlan brief"
        register: vlan_db

      - name: compare vlan_id(.*)Ports against the vlan_db 
        set_fact:
          fact1: "{{ item.1.vlan_id }}"
          fact2: "{{ item.1.sap.inventory_hostname | join(', ') }}" 
          fact3: "{{ fact1 }}(.*){{ fact2 }}"
        failed_when: not vlan_db.stdout is regex(fact3)
        when: inventory_hostname in item.1.sap
        with_subelements:
          -  "{{ customers }}"
          -  services

  1. 我从开关收集输出

  2. 我想遍历“customer”列表并检查“inventory_hostname”是否列在“services.sap”中

我想我可以通过以下方式做到这一点: when: inventory_hostname in item.1.sap

  1. 如果上述检查为真,我想在 fact3 和第一个任务的标准输出之间进行正则表达式比较,如果第一个任务的标准输出中不存在正则表达式,则引发失败:

    set_fact: fact1: "{{ item.1.vlan_id }}" fact2: "{{ item.1.sap.inventory_hostname | join(', ') }}" fact3: "{{ fact1 }}(.*){{ fact2 }}" failed_when: not vlan_db.stdout is regex(fact3)

这就像嵌套循环和条件在一起。有没有办法用 Ansible 做到这一点?我做错了什么?

只是为了确保我的意图是明确的:

/vars/all.yml 看起来像这样:


    customers:
        - name: "cust-1"
          l3_vni: "101"
          services:
            - vlan_id: "10"
              vni: "1010"
              gw: "10.0.0.254/24"
              sap: 
                leaf-1: ["Eth3"]
                leaf-2: ["Eth3"]

            - vlan_id: "11"
              vni: "1011"
              gw: "10.0.1.254/24"
              sap: 
                leaf-1: ["Eth3"]
                leaf-2: ["Eth3"]

        - name: "cust-2"
          l3_vni: "102"
          services:
            - vlan_id: "20"
              vni: "1020"
              gw: "20.0.0.254/24"
              sap: 
                leaf-3: ["Eth3", "Eth4"]
                leaf-4: ["Eth3"]

            - vlan_id: "21"
              vni: "1021"
              gw: "20.0.1.254/24"
              sap: 
                leaf-3: ["Eth3"]
                leaf-4: ["Eth3"]
    ```

    a switch vlan database usually looks like this:

    ```
    leaf-1#show vlan brief

    VLAN Name                             Status    Ports
    ---- -------------------------------- --------- ----------------------
    1    default                          active    Eth5
    10   cust-1                           active    Eth3, Eth4
    20   cust-2                           active    Eth1, Eth2
    ```

error log:

致命的:[leaf-1]:失败!=> { "msg": "该任务包含一个带有未定义变量的选项。错误是:'fact1' 未定义\n\n错误似乎在 '/vagrant/Ansible Folder Setup/NetAutHardWay/Step4-CICD/ vlan_test.yml':第 23 行,第 7 列,但可能\n位于文件中的其他位置,具体取决于确切的语法问题。\n\n违规行似乎是:\n\n\n - 名称:比较 vlan_id(.* )针对 vlan_db 的端口\n ^ here\n" }


标签: ansiblejinja2

解决方案


这里有几个问题。

首先,您的剧本在语法上是无效的:它根本无法运行。它将失败并出现以下错误:

ERROR! unexpected parameter type in action: <class 'ansible.parsing.yaml.objects.AnsibleSequence'>

这是因为 的内容set_fact应该是字典,而不是列表:

- name: "compare vlan_id(.*)Ports against the vlan_db"
  set_fact:
    fact1: "{{ item.1.vlan_id }}"
    fact2: "{{ item.1.sap.inventory_hostname | join(', ') }}"
    fact3: "{{ fact1 }}(.*){{ fact2 }}"
  failed_when: not vlan_db.stdout is regex(fact3)
  when: inventory_hostname in item.1.sap
  with_subelements:
    - "{{ customers }}"
    - services

但是,您在这里遇到了另一个问题:您的事实在任务运行之后才可用set_fact,因此您正在检查的条件is regex(fact3)永远不会正确匹配。如果要使用该表达式的值,则需要将该值公开为变量。

但在我们看之前,还有另一个问题:当你写:

fact2: "{{ item.1.sap.inventory_hostname | join(', ') }}"

sap您正在字典中查找名为“inventory_hostname”的文字键。请记住,当您编写 时foo.bar.baz,这实际上是 . 的简写foo["bar"]["baz"]。你需要:

fact2: "{{ item.1.sap[inventory_hostname] | join(', ') }}"

所以,回到变量。如果您想fact3在条件中使用 的值,有几种方法可以做到这一点。一种选择是在您的任务上使用一个vars块,它会创建在任务期间存在的新变量。我在这里使用了一个debug任务来演示正在发生的事情;set_fact如果您需要在任务完成后保留部分或全部这些变量,您显然可以用任务替换它:

    - name: "compare vlan_id(.*)Ports against the vlan_db"
      debug:
        msg:
          - "{{ fact1 }}"
          - "{{ fact2 }}"
          - "{{ fact3 }}"
      vars:
        fact1: "{{ item.1.vlan_id }}"
        fact2: "{{ item.1.sap[inventory_hostname] | join(', ') }}"
        fact3: "{{ fact1 }}(.*){{ fact2 }}"
      failed_when: not vlan_db.stdout is regex(fact3)
      when: inventory_hostname in item.1.sap
      with_subelements:
        - "{{ customers }}"
        - services

希望这足以为您指明正确的方向。让我知道我是否可以澄清任何事情。


推荐阅读