srv_ER
srv_ER

Reputation: 133

Ansible: Add values in nested dictionary among them selves and insert into another dictionary

I am iterating over the following dictionary of dictionaries and want to add the values of nested dictionary and insert them into another dictionary.

master_nodes

ok: [127.0.0.1] => {
    "msg": {
        "master01.example.com": {
            "cpu_total": 8,
            "cpu_used": 0.22
        },
        "master02.example.com": {
            "cpu_total": 8,
            "cpu_used": 0.27
        },
        "master03.example.com": {
            "cpu_total": 8,
            "cpu_used": 0.22
        }
    }
}

I am trying something like this and struggling to devise a solution.

- name: Total section for master nodes
  set_fact:
    total_master: "{{ (total_master | default({}))| combine({ 'total_cpu' : total_cpu+(item.value.cpu_total|int) }) }} "
  with_dict: "{{ master_nodes }}"

What I am trying achieve in total_master

ok: [127.0.0.1] => {
    "msg": {
        "total_cpu": 24,
        "total_used_cpu": 0.71
    }
}

Upvotes: 0

Views: 522

Answers (4)

wallstalk
wallstalk

Reputation: 83

No loop solution:

    - set_fact:
        cpu_total: "{{ nodes2items | map(attribute='value.cpu_total') | sum | float }}"
        cpu_used: "{{ nodes2items | map(attribute='value.cpu_used') | sum | float }}"
      vars:
        # cast master nodes to items, so it's easier to map
        nodes2items: "{{ master_nodes | dict2items }}"

Upvotes: 0

srv_ER
srv_ER

Reputation: 133

Thanks for your replies. This is how I did it.

- name: Total section for master nodes
  set_fact:
    master_cpu: "{{ (master_cpu|float) + (item.value.cpu_total|float)}}"
    master_cpu_used: "{{ (master_cpu_used|float |round(2,'ceil')) + (item.value.cpu_used|float |round(2,'ceil'))}}"
  with_dict: "{{master_nodes}}"

Upvotes: 0

Moon
Moon

Reputation: 3037

This could be one option:

- set_fact:
    result: "{{ result | default({}) | combine({ item: master_nodes | json_query('@.*') | sum(attribute=item)}) }}"
  loop:
    - cpu_total
    - cpu_used

- debug: 
    var: result

gives

ok: [localhost] => 
  result:
    cpu_total: 24
    cpu_used: 0.71

Another flavour,

- set_fact:
    result: "{{ { 
        'total_cpu': master_nodes | json_query('@.*.cpu_total') | sum(),
        'total_cpu_used': master_nodes | json_query('@.*.cpu_used') | sum()
      } }}"

- debug: 
    var: result

gives

ok: [localhost] => 
  result:
    total_cpu: 24
    total_cpu_used: 0.71

Upvotes: 3

LevB
LevB

Reputation: 953

A nested loop should work.

sum1 = 0
sum2 = 0
for val in dict.values():
    for val1 in val.values():
        sum1+=val1['cpu_total']
        sum2+=val1['cpu_used']

result = 
{
    "msg": {
         "total_cpu": sum1,
         "total_used_cpu": sum2 
    }
}   

print(result)

Output:

{'msg': {'total_cpu': 24, 'total_used_cpu': 0.71}}

Upvotes: 0

Related Questions