terraformfor-in-loophcl

TERRAFORM: Modify Values for ZipMap while Transforming Map to new Keys


I thought this would be easy :frowning:

Goal is to transform this map:

```
accounts = {
  "acct-key-1" = {
    "billingcode" = "sys"
    "future-key" = "SOME-UNIQUE-VALUE-1"
    "private-attribute-1" = "fee"
    "private-attribute-2" = "foe"
  }
  "acct-key-2" = {
    "billingcode" = "sys"
    "future-key" = "SOME-UNIQUE-VALUE-2"
    "private-attribute-1" = "fie"
    "private-attribute-2" = "fum"
  }
}
```  

into this map:

```
goodness = {
  "SOME-UNIQUE-VALUE-1" = {
      "billingcode" = "sys"
      "acct-key" = "acct-key-1" 
  }
  "SOME-UNIQUE-VALUE-2" = {
      "billingcode" = "sys"
      "acct-key" = "acct-key-2"
  }
}
```

As you can see, there are three tasks going on:

  1. Create the new map using a guaranteed-unique attribute (future-key) as the key for the new map. That's not a problem, see code below.
  2. Insert the old key as an attribute into the new map
  3. Remove some named attributes (private-attribute-n) from the new map

Per code below, ZipMap seems to be the way to go partway there. Using ZipMap I get a partial result like this:

```
partial = {
  "SOME-UNIQUE-VALUE-1" = {
    "billingcode" = "sys"
    "future-key" = "SOME-UNIQUE-VALUE-1"
    "private-attribute-1" = "fee"
    "private-attribute-2" = "foe"
  }
  "SOME-UNIQUE-VALUE-2" = {
    "billingcode" = "sys"
    "future-key" = "SOME-UNIQUE-VALUE-2"
    "private-attribute-1" = "fie"
    "private-attribute-2" = "fum"
  }
}
```

with a few things wrong with it:

It seems that "all" I need to do is to modify local.newvalues to:

And I've tried nearly every variant of nested for..in loops I could think of and find on the web, with no success at all, not even enough to show.

The problem seems to be that local.newvalues is a tuple, and methods to modify tuples are few and far between.

The logic I've tried to implement would go like:

for each object in local.newvalues get the corresponding old key from keys(accts) and insert it look at other attributes and skip or remove them if they match one of the private keys

The code is simple and goes like this:

```
locals {
    # get source map
    accts = jsondecode(file("${path.module}/question.json"))
    newkeys = values(local.accts)[*].future-key
    newvalues = values(local.accts)
    partial = zipmap(
      local.newkeys, local.newvalues
    )
}

output "accounts" {
    value = local.accts
}

output "newkeys" {
    value = local.newkeys
}

output "newvalues" {
    value = local.newvalues
}

output "partial" {
    value = local.partial
}```

And the unfinished output like this:

```
Outputs:

accounts = {
  "acct-key-1" = {
    "billingcode" = "sys"
    "future-key" = "SOME-UNIQUE-VALUE-1"
    "private-attribute-1" = "fee"
    "private-attribute-2" = "foe"
  }
  "acct-key-2" = {
    "billingcode" = "sys"
    "future-key" = "SOME-UNIQUE-VALUE-2"
    "private-attribute-1" = "fie"
    "private-attribute-2" = "fum"
  }
}
newkeys = [
  "SOME-UNIQUE-VALUE-1",
  "SOME-UNIQUE-VALUE-2",
]
newvalues = [
  {
    "billingcode" = "sys"
    "future-key" = "SOME-UNIQUE-VALUE-1"
    "private-attribute-1" = "fee"
    "private-attribute-2" = "foe"
  },
  {
    "billingcode" = "sys"
    "future-key" = "SOME-UNIQUE-VALUE-2"
    "private-attribute-1" = "fie"
    "private-attribute-2" = "fum"
  },
]
partial = {
  "SOME-UNIQUE-VALUE-1" = {
    "billingcode" = "sys"
    "future-key" = "SOME-UNIQUE-VALUE-1"
    "private-attribute-1" = "fee"
    "private-attribute-2" = "foe"
  }
  "SOME-UNIQUE-VALUE-2" = {
    "billingcode" = "sys"
    "future-key" = "SOME-UNIQUE-VALUE-2"
    "private-attribute-1" = "fie"
    "private-attribute-2" = "fum"
  }
}

To make code easy to reproduce, I put the initial map in a json file that the code reads and decodes; here it is as question.json:

```
{
    "acct-key-1": {
        "future-key": "SOME-UNIQUE-VALUE-1",
        "billingcode": "sys",
        "private-attribute-1": "fee",
        "private-attribute-2": "foe"
    },
    "acct-key-2": {
        "future-key": "SOME-UNIQUE-VALUE-2",
        "billingcode": "sys",
        "private-attribute-1": "fie",
        "private-attribute-2": "fum"
    }  
}
```

Ideas much appreciated


Solution

  • You do not need zip for that. Just a single for loop is enough:

    
    locals {
      goodness = {
        for acc_key, acc_details in local.accts:
          acc_details.future-key => {
            acct-key = acc_key
            billingcode = acc_details.billingcode
          }
      }
    }
    

    which gives:

    {
      "SOME-UNIQUE-VALUE-1" = {
        "acct-key" = "acct-key-1"
        "billingcode" = "sys"
      }
      "SOME-UNIQUE-VALUE-2" = {
        "acct-key" = "acct-key-2"
        "billingcode" = "sys"
      }
    }