Home > OS >  Ansible data manipulation - List trasformation
Ansible data manipulation - List trasformation

Time:12-24

I need to transform a simple list to a complex one.

The simple one looks like:

customers:
  - customer01-node01.private.foo.it
  - customer02-node01.private.foo.it
  - customer04-node03.private.foo.it
  - customer03-node02.private.foo.it
  - customer05-node02.private.foo.it
  - customer01-node04.private.foo.it
  - cusotmer02-node04.private.foo.it
  - customer04-node06.private.foo.it
  - customer03-node05.private.foo.it
  - customer05-node05.private.foo.it

I am trying to find a way to obtain a complex one, grouping nodes by customer. The final result I'm finding for is this one:

customers_list:
  - customer: customer01
    nodes:
      - node01.private.foo.it
      - node04.private.foo.it
  - customer: customer02
    nodes:
      - node01.private.foo.it
      - node04.private.foo.it
  - customer: customer03
    nodes:
      - node02.private.foo.it
      - node05.private.foo.it
  - customer: customer04
    nodes:
      - node03.private.foo.it
      - node06.private.foo.it
  - customer: customer05
    nodes:
      - node02.private.foo.it
      - node05.private.foo.it

I am unable to find a way.

CodePudding user response:

Parse the data

    - set_fact:
        customers_parsed: "{{ customers_parsed|d([])   [{'customer': _customer,
                                                         'node': _node}] }}"
      loop: "{{ customers }}"
      vars:
        _customer: "{{ item.split('-')|first }}"
        _node: "{{ item.split('-')|last }}"

gives

  customers_parsed:
  - customer: customer01
    node: node01.private.foo.it
  - customer: customer02
    node: node01.private.foo.it
  - customer: customer04
    node: node03.private.foo.it
  - customer: customer03
    node: node02.private.foo.it
  - customer: customer05
    node: node02.private.foo.it
  - customer: customer01
    node: node04.private.foo.it
  - customer: customer02
    node: node04.private.foo.it
  - customer: customer04
    node: node06.private.foo.it
  - customer: customer03
    node: node05.private.foo.it
  - customer: customer05
    node: node05.private.foo.it

Then group the items by the attribute customer and concatenate the list

    - set_fact:
        customers_list: "{{ customers_list|d([])   [{'customer': item.0,
                                                     'nodes': _nodes}] }}"
      loop: "{{ customers_parsed|groupby('customer') }}"
      vars:
        _nodes: "{{ item.1|map(attribute='node')|list }}"

gives

  customers_list:
  - customer: customer01
    nodes:
    - node01.private.foo.it
    - node04.private.foo.it
  - customer: customer02
    nodes:
    - node01.private.foo.it
    - node04.private.foo.it
  - customer: customer03
    nodes:
    - node02.private.foo.it
    - node05.private.foo.it
  - customer: customer04
    nodes:
    - node03.private.foo.it
    - node06.private.foo.it
  - customer: customer05
    nodes:
    - node02.private.foo.it
    - node05.private.foo.it

CodePudding user response:

you could use a custom filter:

you create a folder filter_plugins in your playbook folder (i have named the file myfilters.py and the filter custom)

myfilters.py:

#!/usr/bin/python
class FilterModule(object):
    def filters(self):
        return {
            'custom': self.custom
        }

    def custom(self, listvar):
        result = {}
        final = []
        for it in listvar:
            f, s = it.split('-')
            if f in result:
                result[f].append(s)
            else:
                result[f] = [s]
        
        for k in result:
            final.append({'customer':k, 'nodes': result[k]})

        return final

the playbook:

---
- hosts: localhost
  vars:
    customers:
      - customer01-node01.private.foo.it
      - customer02-node01.private.foo.it
      - customer04-node03.private.foo.it
      - customer03-node02.private.foo.it
      - customer05-node02.private.foo.it
      - customer01-node04.private.foo.it
      - customer02-node04.private.foo.it
      - customer04-node06.private.foo.it
      - customer03-node05.private.foo.it
      - customer05-node05.private.foo.it
  tasks:
    - name: parsevar
      set_fact: 
        customers_list: "{{ customers | custom }}"
        
    - name: display
      debug: 
        msg: "{{ customers_list }}"

result:

ok: [localhost] => {
    "msg": [
        {
            "customer": "customer01",
            "nodes": [
                "node01.private.foo.it",
                "node04.private.foo.it"
            ]
        },
        {
            "customer": "customer02",
            "nodes": [
                "node01.private.foo.it",
                "node04.private.foo.it"
            ]
        },
        {
            "customer": "customer04",
            "nodes": [
                "node03.private.foo.it",
                "node06.private.foo.it"
            ]
        },
        {
            "customer": "customer03",
            "nodes": [
                "node02.private.foo.it",
                "node05.private.foo.it"
            ]
        },
        {
            "customer": "customer05",
            "nodes": [
                "node02.private.foo.it",
                "node05.private.foo.it"
            ]
        }
    ]
}

the advantage to use a custom filter: you just have only one task to transform datas

  • Related