Home > Blockchain >  Ansible - format output list from loop (need all results, not only the last one)
Ansible - format output list from loop (need all results, not only the last one)

Time:10-07

I have a dict with which I'm doing simple arithmetic operations. That is fine, but when I print result I just get the result for the last key-value pair, not for all of them.

Thanks.

    - hosts: localhost
      gather_facts: false
    
      vars:
        dict1: [{x: 1, y: 2},{x: 3, y: 4},{x: 5, y: 6}]
    
      tasks:
      - set_fact:
          percentage: "{{ item.x / item.y * 100}}"
        with_items: "{{dict1}}"
>ok: [localhost] => (item={'x': 1, 'y': 2}) => {
    "ansible_facts": {
        "percentage": "50.0"
    },
    "ansible_loop_var": "item",
    "changed": false,
    "item": {
        "x": 1,
        "y": 2
    }
}
>ok: [localhost] => (item={'x': 3, 'y': 4}) => {
    "ansible_facts": {
        "percentage": "75.0"
    },
    "ansible_loop_var": "item",
    "changed": false,
    "item": {
        "x": 3,
        "y": 4
    }
}
>ok: [localhost] => (item={'x': 5, 'y': 6}) => {
    "ansible_facts": {
        "percentage": "83.33333333333334"
    },
    "ansible_loop_var": "item",
    "changed": false,
    "item": {
        "x": 5,
        "y": 6
    }
}

Result when I print it:


    debug:
      msg: "{{ percentage }}"

It's only the last value:

ok: [localhost] => { "msg": "83.33333333333334" }

UPDATE (WITH REGISTER):

          - name: Show percentage
            debug:
              msg: "{{ item.x / item.y * 100}}"
            with_items: "{{ dict1 }}"
            register: percentage
        
          - name: Show result
            debug:
              var: percentage # dict
        
          - name: Show result
            debug:
              var: percentage.results # list

RESULT (with not only results, but also item, loop and other informational things I don't need):

>ok: [localhost] => {
    "percentage.results": [
        {
            "ansible_loop_var": "item",
            "changed": false,
            "failed": false,
            "item": {
                "x": 1,
                "y": 2
            },
            "msg": "50.0"
        },
        {
            "ansible_loop_var": "item",
            "changed": false,
            "failed": false,
            "item": {
                "x": 3,
                "y": 4
            },
            "msg": "75.0"
        },
        {
            "ansible_loop_var": "item",
            "changed": false,
            "failed": false,
            "item": {
                "x": 5,
                "y": 6
            },
            "msg": "83.33333333333334"
        }
    ]

}

CodePudding user response:

"I just get the result for the last key-value pair, not for all of them."

That is the expected behavior for the shown set_fact loop since it is registering every loop run the value new.

You may let run the following example

  - name: Show percentage
    debug:
      msg: "{{ item.x / item.y * 100}}"
    with_items: "{{ dict1 }}"
    register: percentage

  - name: Show result
    debug:
      var: percentage # dict

to get familiar with Registering variables and the returned data structure for loop.

When you register a variable in a task with a loop, the registered variable contains a value for each item in the loop. The data structure placed in the variable during the loop will contain a results attribute, that is a list of all responses from the module.


After first test and regarding

Yes, but I get all other info that I don't need need i.e. ansible_loop_var': 'item'}, {'ansible_facts' ... or failed': False, 'changed': False, 'item':.. I need just a list with pure results, without that additional info.

to narrow down you could do further runs with

  - name: Show result
    debug:
      var: percentage.results # list

resulting into an output of

ok: [localhost] =>
  msg:
  - ansible_loop_var: item
    changed: false
    failed: false
    item:
      x: 1
      y: 2
    msg: '50.0'
  - ansible_loop_var: item
    changed: false
    failed: false
    item:
      x: 3
      y: 4
    msg: '75.0'
  - ansible_loop_var: item
    changed: false
    failed: false
    item:
      x: 5
      y: 6
    msg: '83.3333333333'

That is one possible approach for creating a result list.


Follow Up

It seems that you like to have the percentage results only. Therefore it will be necessary to work further on the list to get the values of the msg element out.

A very simple approach and which isn't mentioned for further data processing

  - name: Show result
    debug:
      msg: "{{ item.msg }}"
    loop: "{{ percentage.results }}"
    loop_control:
      label: "{{ item.item }}"

will result into an output of

TASK [Show result] ****************************
ok: [localhost] => (item={u'y': 2, u'x': 1}) =>
  msg: '50.0'
ok: [localhost] => (item={u'y': 4, u'x': 3}) =>
  msg: '75.0'
ok: [localhost] => (item={u'y': 6, u'x': 5}) =>
  msg: '83.3333333333'

CodePudding user response:

Use Jinja to create the list. For example,

percentage: |
  [
  {% for i in dict1 %}
  {{ i.x / i.y }},
  {% endfor %}
  ]

gives

percentage:
  - 0.5
  - 0.75
  - 0.8333333333333334

Example of a complete playbook for testing

- hosts: localhost

  vars:

    dict1: [{x: 1, y: 2},{x: 3, y: 4},{x: 5, y: 6}]
    percentage: |
      [
      {% for i in dict1 %}
      {{ i.x / i.y }},
      {% endfor %}
      ]

  tasks:

    - debug:
        var: percentage|type_debug
    - debug:
        var: percentage
  • Related