3

This is my list of addresses in a YAML file :

addresses:
  person1:
    firstname: Maria
    lastname:  Smith
  person2:
    firstname: July
    lastname:  Weber
  person3:
    firstname: John
    lastname:  Kurt
  person4:
    firstname: Simon
    lastname:  Gates

What i need is a comma separated string like Maria, July, John, Simon

I tried the following:

firstnames: >-
  {% set lastnames_list= [] %}
  {% for name in addresses %}
      {{ name.firstname | join(",")}}
  {% endfor %}
  {{ lastnames_list }} 

firstnames: >-
  {% set lastnames_list= [] %}
  {% for name in addresses %}
      {{ name | map(attribute="firstname") | join(",") }}
  {% endfor %}
  {{ lastnames_list }} 

firstnames: '{{ addresses | map(attribute="firstname") | join(",") }}' 

But Ansible gives the following output:

The task includes an option with an undefined variable. The error was: 'unicode object' has no attribute 'firstname'

β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
ducato66
  • 53
  • 1
  • 3

2 Answers2

3

Simple json_query filter can be used to achieve the result.

- debug:
    msg: '{{ addresses | json_query("@.*.firstname") | join(", ") }}'

gives

ok: [localhost] => 
  msg: Maria, July, John, Simon
Moon
  • 2,837
  • 1
  • 20
  • 34
1

The map filter actually applies a filter on a sequence of objects or looks up an attribute.

But here, you do have a dictionary, not a sequence of objects nor an object with attributes only.

In order to achieve what you are looking for there is two path:

  1. If you stick with your actual YAML structure, you can turn your dict back in a normalized list using Ansible dict2items filter:

    firstnames: "{{ addresses | dict2items | map(attribute='value') | map(attribute='firstname') | join(',') }}"
    
  2. You can switch your dictionary into a list, changing the structure of your list of addresses this way, and then your Jinja will work:

    addresses:
      - firstname: Maria
        lastname:  Smith
      - firstname: July
        lastname:  Weber
      - firstname: John
        lastname:  Kurt
      - firstname: Simon
        lastname:  Gates
    

    Will work with

    firstnames: "{{ addresses | map(attribute='firstname') | join(',') }}" 
    

Here are the working examples and their corresponding recap.

  1. Playbook using dict2items:
    - hosts: local
      gather_facts: no
      vars:
        addresses:
          person1:
            firstname: Maria
            lastname:  Smith
          person2:
            firstname: July
            lastname:  Weber
          person3:
            firstname: John
            lastname:  Kurt
          person4:
            firstname: Simon
            lastname:  Gates
    
      tasks:
        - debug:
            msg: "{{ addresses | dict2items | map(attribute='value') | map(attribute='firstname') | join(',') }}"
    
    Gives the recap:
    PLAY [local]    **************************************************************************************************************
    
    TASK [debug]    **************************************************************************************************************
    ok: [local] => {
        "msg": "Maria,July,John,Simon"
    }
    
    PLAY RECAP    ****************************************************************************************************************
    local                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0     
    
  2. Playbook changing the YAML address structure:
    - hosts: local
      gather_facts: no
      vars:
        addresses:
          - firstname: Maria
            lastname:  Smith
          - firstname: July
            lastname:  Weber
          - firstname: John
            lastname:  Kurt
          - firstname: Simon
            lastname:  Gates
    
      tasks:
        - debug:
            msg: "{{ addresses | map(attribute='firstname') | join(',') }}"
    
    Gives the recap:
    PLAY [local]    **************************************************************************************************************
    
    TASK [debug]    **************************************************************************************************************
    ok: [local] => {
        "msg": "Maria,July,John,Simon"
    }
    
    PLAY RECAP    ****************************************************************************************************************
    local                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  
    
β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
  • Tanks a lot for your reply. I consider changing to a list but the dictionary is used in other places in the playbook.... – ducato66 Jun 21 '20 at 12:08