【问题标题】:Ansible nested loops and conditional together in the same taskAnsible 嵌套循环和条件一起在同一个任务中
【发布时间】:2019-12-06 11:02:55
【问题描述】:
---

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

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

  • 遍历客户列表中的项目
  • 遍历每个客户的服务列表中的项目
  • 检查 item.1.sap 是否有与 inventory_hostname 匹配的键
  • 如果上述检查为真,则将上述正则表达式模式与第一个任务的输出进行比较。

/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(.*)Ports 与vlan_db\n ^ 这里\n" }


【问题讨论】:

    标签: ansible jinja2


    【解决方案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
    

    希望这足以为您指明正确的方向。如果我能澄清任何事情,请告诉我。

    【讨论】:

      【解决方案2】:

      谢谢你。经过一番努力,我能够通过以下游戏实现我的目标。 我还必须更改 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-12
        • 1970-01-01
        • 2015-10-27
        相关资源
        最近更新 更多