skip to Main Content

I am trying to generate Terraform resources from a JSON file that has duplicate keys.
Is there any way to avoid the duplicate?

Here is an example JSON

{
  "my-ptr-zone": {
    "21-10": {
      "zone"  : "21.10.in-addr.arpa"
    },

    "21-10": {
      "zone"  : "21.10.in-addr.arpa"
    }
  }
}

Both the keys are the same here.

And here is the resource

resource "aws_route53_zone" "my-ptr-zone" {
  for_each = var.my-ptr-zone
  name     = each.value.zone
}

Is there any way to skip the duplicates when looping?

I have tried to avoid generating duplicate values in the JSON file from the source, but that is another challenge.

3

Answers


  1. If you want to generate only one resource per unique key in a map, ask Terraform to generate a set of the keys, then loop over those.

    Consider the following example using the hashicorp/random provider.

    locals {
      my-ptr-zone = {
        "21-10" = {
          zone = "21.10.in-addr.arpa"
        }
        "21-10" = {
          zone = "21.10.in-addr.arpa"
        }
      }
    }
    
    resource "random_id" "example" {
      for_each = toset(keys(local.my-ptr-zone))
      byte_length = 8
    }
    

    Planning that with terraform plan, you’ll see that terraform only wants to generate one resource.

    # random_id.example["21-10"] will be created
    + resource "random_id" "example" {
      + b64_std     = (known after apply)
      + b64_url     = (known after apply)
      + byte_length = 8
      + dec         = (known after apply)
      + hex         = (known after apply)
      + id          = (known after apply)
    }
    
    Plan: 1 to add, 0 to change, 0 to destroy.
    

    Change one of the keys to something different, and terraform will want to create two resources.

    # random_id.example["21-10"] will be created
    ...
    
    # random_id.example["21-11"] will be created
    ...
    
    Plan: 2 to add, 0 to change, 0 to destroy.
    

    If you instead are interested in some other uniqueness (e.g. only the unique values of zone), the same approach could be applied … generate a set of the things you want to be unique, then iterate over that set.

    Login or Signup to reply.
  2. A simple way to approach this would be to run a merge on the map twice.

    JSON File:

    {
      "my-ptr-zone": {
        "21-10": {
          "zone"  : "21.10.in-addr.arpa"
        },
    
        "21-10": {
          "zone"  : "21.10.in-addr.arpa"
        }
      }
    }
    

    TF Code:

    locals {
      data  = jsondecode(file("data.json"))
      zones = merge(local.data.my-ptr-zone, local.data.my-ptr-zone)
    }
    
    output "zones" {
      value = local.zones
    }
    
    # This will now be a unique resource
    resource "aws_route53_zone" "my-ptr-zone" {
      for_each = local.zones
      name     = each.value.zone
    }
    

    Output:

    Outputs:
    
    zones = {
      "21-10" = {
        "zone" = "21.10.in-addr.arpa"
      }
    }
    
    Login or Signup to reply.
  3. Terraform’s jsondecode function reacts to duplicate property names in a single object by discarding all but the last definition of a particular name.

    In the example shown in your question, jsondecode of the JSON document shown would produce the following Terraform value:

    {
      "my-ptr-zone" = {
        "21-10" = {
          "zone" = "21.10.in-addr.arpa"
        }
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search