Convert one structure into another

Hello,
I’m trying convert source object:

local.map_auto_ip
{
  "appliance" = {}
  "mgmt" = {
    "tfbs11is" = "10.130.0.1"
    "tfcp10" = "10.130.0.2"
    "tfds20" = "10.130.0.3"
    "tfhv01centos7kvm" = "10.130.0.4"
  }
  "provisioning" = {
    "tfcp10" = "10.134.0.1"
    "tfhv01centos7kvm" = "10.134.0.2"
  }
  "public" = {}
  "storage" = {
    "tfbs11is" = "10.131.0.1"
    "tfds20" = "10.131.0.2"
    "tfhv01centos7kvm" = "10.131.0.3"
  }
}

Into this, but I’m trying many variants how to do this but unfortunately can’t find solution…

Of course public and appliance could be used too. Number of addresses can be different.

It is possible to do this?

{
  "tfbs11is" = {
    "mgmt" = "10.130.0.1"
    "storage" = "10.131.0.1"
  },
  "tfcp10" = {
    "mgmt" = "10.130.0.2"
    "provisioning" = "10.134.0.1"
  },
  "tfds20" = {
    "mgmt" ="10.130.0.3"
    "storage" = "10.131.0.2"
  }
  "tfhv01centos7kvm" = {
    "mgmt" = "10.130.0.4"
    "provisioning" = "10.134.0.2"
    "storage" = "10.131.0.3"
  }
}

PS. The last my try is, but result is wrong… And I don’t understand why ‘k’ key not used…

[ for k,v in local.map_auto_ip: {for x,y in v: x=>{k = y} } ]

[
  {},
  {
    "tfbs11is" = {
      "k" = "10.130.0.1"
    }
    "tfcp10" = {
      "k" = "10.130.0.2"
    }
    "tfds20" = {
      "k" = "10.130.0.3"
    }
    "tfhv01centos7kvm" = {
      "k" = "10.130.0.4"
    }
  },
  {
    "tfcp10" = {
      "k" = "10.134.0.1"
    }
    "tfhv01centos7kvm" = {
      "k" = "10.134.0.2"
    }
  },
  {},
  {
    "tfbs11is" = {
      "k" = "10.131.0.1"
    }
    "tfds20" = {
      "k" = "10.131.0.2"
    }
    "tfhv01centos7kvm" = {
      "k" = "10.131.0.3"
    }
  },
]

Okay… this one looks better :slight_smile: but I need to unite by keys: tfbs11is, tfcp10

[ for k, v in local.map_auto_ip: {for x, y in v: x=>{"${k}" = y} } ]

[
  {},
  {
    "tfbs11is" = {
      "mgmt" = "10.130.0.3"
    }
    "tfcp10" = {
      "mgmt" = "10.130.0.4"
    }
    "tfds20" = {
      "mgmt" = "10.130.0.5"
    }
    "tfhv01centos7kvm" = {
      "mgmt" = "10.130.0.6"
    }
  },
  {
    "tfcp10" = {
      "provisioning" = "10.134.0.3"
    }
    "tfhv01centos7kvm" = {
      "provisioning" = "10.134.0.4"
    }
  },
  {},
  {
    "tfbs11is" = {
      "storage" = "10.131.0.3"
    }
    "tfds20" = {
      "storage" = "10.131.0.4"
    }
    "tfhv01centos7kvm" = {
      "storage" = "10.131.0.5"
    }
  },
]

Hello,

Any idea? How to unite this objects by key?

Hi @skydion. I think what you want to do here is possible, although it’s quite involved!

Below is a commented configuration, which I think produces the result you mentioned. Let me know if anything’s unclear or if it doesn’t do what you’re looking for.

locals {
  map_auto_ip = {
    "appliance" = {}
    "mgmt" = {
      "tfbs11is" = "10.130.0.1"
      "tfcp10" = "10.130.0.2"
      "tfds20" = "10.130.0.3"
      "tfhv01centos7kvm" = "10.130.0.4"
    }
    "provisioning" = {
      "tfcp10" = "10.134.0.1"
      "tfhv01centos7kvm" = "10.134.0.2"
    }
    "public" = {}
    "storage" = {
      "tfbs11is" = "10.131.0.1"
      "tfds20" = "10.131.0.2"
      "tfhv01centos7kvm" = "10.131.0.3"
    }
  }

  # This separator is used for an intermediate step where we build a flattened
  # map with a composite key, for later splitting. This string must not appear
  # in the type or host.
  sep = "___"

  # Flatten out the nested map structure, partially inverting it, using a unique
  # composite key.
  flattened = merge([ 
    for type, host_ip_map in local.map_auto_ip: {
      for host, ip in host_ip_map: join(local.sep, [host, type]) => ip
    }
  ]...)

  # Use the trailing ... grouping operator on the for expression to generate a
  # map from host to a collection of one-element maps, from type to IP.
  map_of_tuples = {
    for k, ip in local.flattened:
      split(local.sep, k)[0] => { split(local.sep, k)[1] : ip }...
    }

  # Merge all the one-element maps to give the desired final result.
  result = {
    for k, tuples in local.map_of_tuples:
      k => merge(tuples...)
    }
}

output "result" {
  value = local.result
}

Hi @alisdair

You are genius! Nice and unusual solution. All clear and work fine!
Thank you