Ansible嵌套循环和条件循环在同一任务中

时间:2019-12-06 11:02:55

标签: ansible jinja2

---

    - 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. 我想遍历“客户”列表,并检查“ services.sap”中是否列出了“ inventory_hostname”

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

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

    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做到这一点? 我在做什么错了?

只是要确保我的意图明确:

  • 循环浏览客户列表中的项目
  • 循环浏览每个客户的服务列表中的项目
  • 检查item.1.sap是否具有与清单主机名匹配的密钥
  • 如果上述检查为真,则在上面的正则表达式模式和第一个任务的输出之间进行比较。

/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 ^这里\ n“ }


2 个答案:

答案 0 :(得分:1)

这里有几个问题。

首先,您的剧本在语法上无效:它根本不会运行。它将失败并显示错误:

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

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

答案 1 :(得分:0)

感谢幼虫。经过一番挣扎,我得以通过以下比赛实现自己的目标。 我还必须更改failed_when语法。

- hosts: leaf-1
  gather_facts: no 
  tags: [ verify ]
  vars_files: 
    - ../Step2-config/roles/services_config/vars/main.yml

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

    - debug: 
        var: vlan_db.stdout
        var: inventory_hostname, vlan_db        

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