Sum value from a list comparing with other list in Ansible

Viewed 51
virt_server:                       
  - name: server5
    pri_sys: prd1
    sec_sys: cont1
    proc: 0.7

  - name: server6
    pri_sys: prd2
    sec_sys: cont2
    proc: 1.0

  - name: server7
    pri_sys: prd1
    sec_sys: cont1
    proc: 1.0

phys_server:
  - name: PRD1 
  - name: PRD2
  - name: CONT1
  - name: CONT2
  - name: DR

I want to sum the value proc of the virt_server that belong to each phys_server. I tried to make a nested loop when pri_sys is equal to phys_server.name. It have to sum and store in a variable.

I expect the following list:

phys_proc:
  - name: PRD1
    proc_total: 1.7
  - name: PRD2
    proc_total: 1.0
1 Answers

You don't need a nested loop, as there are Jinja filters to filter lists of dictionaries that can do what you need with a single loop.

Namely, the filter you want to look for is selectattr that gives you the possibility to filter a list of dictionary based on a test.

So, here would be the fact you are looking for:

- set_fact:
    phys_proc: >-
      {{ 
        phys_proc | default([]) 
        + [{
          'name': item.name, 
          'proc_total': virt_server
            | selectattr('pri_sys', '==', item.name | lower)
            | sum(attribute="proc") 
            | float
        }]
      }}
  loop: "{{ phys_server }}"
  loop_control:
    label: "{{ item.name }}"

This would give you the full list of all the physical servers. If you only want those that have a total of processor used greater than zero, you can use a selectattr, once again:

- debug:
    var: phys_proc | selectattr('proc_total', '>', 0) 

Given the playbook

- hosts: localhost
  gather_facts: no

  tasks:
    - set_fact:
        phys_proc: >-
          {{ 
            phys_proc | default([]) 
            + [{
              'name': item.name, 
              'proc_total': virt_server
                | selectattr('pri_sys', '==', item.name | lower)
                | sum(attribute="proc") 
                | float
            }]
          }}
      loop: "{{ phys_server }}"
      loop_control:
        label: "{{ item.name }}"
      vars:
        virt_server:                       
          - name: server5
            pri_sys: prd1
            sec_sys: cont1
            proc: 0.7

          - name: server6
            pri_sys: prd2
            sec_sys: cont2
            proc: 1.0

          - name: server7
            pri_sys: prd1
            sec_sys: cont1
            proc: 1.0

        phys_server:
          - name: PRD1 
          - name: PRD2
          - name: CONT1
          - name: CONT2
          - name: DR
    
    - debug:
        var: phys_proc

    - debug:
        var: phys_proc | selectattr('proc_total', '>', 0)

This yields:

TASK [set_fact] *******************************************************
ok: [localhost] => (item=PRD1)
ok: [localhost] => (item=PRD2)
ok: [localhost] => (item=CONT1)
ok: [localhost] => (item=CONT2)
ok: [localhost] => (item=DR)

TASK [debug] **********************************************************
ok: [localhost] => 
  phys_proc:
  - name: PRD1
    proc_total: 1.7
  - name: PRD2
    proc_total: 1.0
  - name: CONT1
    proc_total: 0.0
  - name: CONT2
    proc_total: 0.0
  - name: DR
    proc_total: 0.0

TASK [debug] **********************************************************
ok: [localhost] => 
  phys_proc | selectattr('proc_total', '>', 0):
  - name: PRD1
    proc_total: 1.7
  - name: PRD2
    proc_total: 1.0
Related