首页 > 解决方案 > Complex with_subelements construct

问题描述

I have the list:

    final_list:
      - result:
          name: "val1"
          status: true 
      - result:
          name: "val2"
          status: true
      - skipped:
          path: "path1"
      - result:
          results:
            - result:
                name: "val4"
                status: true
            - result:
                name: "val5"
                status: true
            - skipped:
                path: "path2"

I would like check if any status in my list is false. I started with:

- set_fact:
    any_false: true
  when: (item.0.result is defined and item.0.result.status == false) or (item.1.result is defined and item.1.result.status == false) 
  with_subelements:
    - "{{ final_list }}"
    - result.results"
    - skip_missing: True

but this task ommit elements from finally_list without results in result. I would expect iterate by all elements which contain status variable.

I tried also:

  with_subelements:
    - "{{ final_list }}"
    - result.results | default([])

but get error:

msg: msg: the key result should point to a dictionary, got 'None'

标签: ansible

解决方案


I suggest to do this a bit differently: get all individual result elements in a single flattened list, extract the status and check that all elements are true (or not).

The following playbook should be self explanatory (run with -v to see intermediate debug)

---
- hosts: localhost
  gather_facts: false

  vars:

    final_list:
      - result:
          name: "val1"
          status: true
      - result:
          results:
            - result:
                name: "valA"
                status: false
            - result:
                name: "valB"
                status: true
            - skipped:
                path: "path2"
      - result:
          name: "val2"
          status: true
      - skipped:
          path: "path1"
      - result:
          results:
            - result:
                name: "val4"
                status: true
            - result:
                name: "val5"
                status: true
            - skipped:
                path: "path2"

    # List of all top level elements without nested elements
    single_results: "{{ final_list | rejectattr('result.results', 'defined') }}"

    # Flattened list of all nested result elements.
    # Will work with several nested elements (as you can see from my example data)
    nested_results: "{{ final_list | selectattr('result.results', 'defined') | map(attribute='result.results') | flatten }}"

    # Single list containing top level + nested result elements
    all_results: "{{ single_results + nested_results }}"

    # List of all existing status values in the list of result elements
    all_status: "{{ all_results | selectattr('result.status', 'defined') | map(attribute='result.status') }}"

  tasks:
    - name: Show entire list
      debug:
        var: all_results
        verbosity: 1

    - name: Show list of status
      debug:
        var: all_status
        verbosity: 1

    - name: Make sure all exsiting status are true
      assert:
        that:
          - all_status is all
        fail_msg: "At least one status is false"
        success_msg: "All status are true"

which gives:

PLAY [localhost] ***********************************************************************************************************************************************************************************************************************

TASK [Show entire list] ****************************************************************************************************************************************************************************************************************
skipping: [localhost]

TASK [Show list of status] *************************************************************************************************************************************************************************************************************
skipping: [localhost]

TASK [Make sure all exsiting status are true] ******************************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {
    "assertion": "all_status is all",
    "changed": false,
    "evaluated_to": false,
    "msg": "At least one status is false"
}

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

And if you modify the data to all true (only pasting the last task...)

TASK [Make sure all exsiting status are true] ******************************************************************************************************************************************************************************************
ok: [localhost] => {
    "changed": false,
    "msg": "All status are true"
}

推荐阅读