dei
dei

Reputation: 53

Reduce Ansible list of objects to a single string of concatenated object values

I am trying to parse the output of elasticache_facts ansible module, to extract the IPS and the ports of the memcached nodes in a string of the form "addr1: port1 addr2:port2 ..."(I want to store this string in a configmap to be used in an app).

Basically I want to take two fields "address" and "port" from a list of dicts like this:

list1:
- endpoint: 
    address: "addr1"
    port: "port1"
- endpoint: 
    address: "addr2"
    port: "port2"

and to concatenate them like above.

I have a ugly solution that goes like this:

# register the output of the facts to something I know
elasticache_facts:
  region: "{{ terraform.region }}"
  name: "{{ cluster }}-{{ env }}"
register: elasticache

#declare an empty var in vars file to be used as accumulator
memcache_hosts: ""

# iterate through the list of nodes and append the fields to my string; I will have some extra spaces(separators) but that's ok
set_fact:
  memcache_hosts: "{{ memcache_hosts }} {{item.endpoint.address}}:{{item.endpoint.port}}"
with_items: "{{ elasticache.elasticache_clusters[0].cache_nodes}}"

Is there some less ugly way to filter the list to the desired format?

Maybe there is a magic filter I don't know about?

I can also obtain two lists, one with hosts, one with ports, zip them, make a dict out of that, but I found only some ugly to_json and then regex to make it a string. I am also considering to write a custom filter in python, but seems also overdoing it.

Thanks for the help!

Upvotes: 3

Views: 5745

Answers (1)

Nick
Nick

Reputation: 2034

Here are two ways to achieve what you are looking for:

#!/usr/bin/env ansible-playbook
---
- name: Lets munge some data
  hosts: localhost
  become: false
  gather_facts: false
  vars:
    my_list:
    - address: '10.0.0.0'
      port: '80' 
    - address: '10.0.0.1'
      port: '88' 
  tasks:
  - name: Quicky and dirty inline jinja2
    debug: 
      msg: "{% for item in my_list %}{{ item.address }}:{{ item.port }}{% if not loop.last %} {% endif %}{% endfor %}"

  # Note the to_json | from_json workaround for https://github.com/ansible/ansible/issues/27299
  - name: Using JSON Query
    vars:
      jmes_path: "join(':', [address, port])"
    debug: 
      msg: "{{ my_list | to_json | from_json | map('json_query', jmes_path) | join(' ') }}"

The above outputs:

PLAY [Lets munge some data] **********************************************************************************************************************************

TASK [Quicky and dirty inline jinja2] ************************************************************************************************************************
ok: [localhost] => {
    "msg": "10.0.0.0:80 10.0.0.1:88"
}

TASK [Using JSON Query] **************************************************************************************************************************************
ok: [localhost] => {
    "msg": "10.0.0.0:80 10.0.0.1:88"
}

PLAY RECAP ***************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0   

Upvotes: 6

Related Questions