2

I'm trying to create a dynamic method to create vms in multiple environments that will be configured by the end user. Tried for loops with nested loops. flatten function, count, etc but haven't found a way to reach my goal. I have terrafrom.tfvars with the follwing structure:

Bigip_devices = {
    main_hub = {
      region             = "eastus"
      azs                = ["1"]            #Azure availabilty zones
      vnet_name               = "vnet-main"   # Vnet name to deploy to
      bigip_instance_count = 2            # Number of instnaces to delpoy
      cluster             = "yes"         # Deploy as a cluster or stand alone device
      version             = ""            # Leave blank for default value
      sku                 = ""            # Leave blank for default value - f5-bigip-virtual-edition-25m-best-hourly
      offer               = ""            # Leave blank for default value - f5-big-ip-best
      instance_type       = ""            # Leave blank for default value - Standard_DS3_v2
      disable_password_authentication = ""     #Leave blank for default value
      tags                = ""
    }
    spoke = {
      region             = "eastus"
      azs                = ["1","2"]            #Azure availabilty zones
      vnet_name               = "vnet-spoke"   # Vnet name to deploy to
      bigip_instance_count = 4            # Number of instnaces to delpoy
      cluster             = "yes"         # Deploy as a cluster or stand alone device
      version             = ""            # Leave blank for default value
      sku                 = ""            # Leave blank for default value - f5-bigip-virtual-edition-25m-best-hourly
      offer               = ""            # Leave blank for default value - f5-big-ip-best
      instance_type       = ""            # Leave blank for default value - Standard_DS3_v2
      disable_password_authentication = ""     #Leave blank for default value
      tags                = ""
    }
  }

What is the correct method to iterate each key in the list( in the example the are 2 keys - main hub and spoke) and to create the amount of virtual machines corresponding to the bigip_instance_count setting. In the above example, I want to create 2 environments, one with 2 devices and the second with 4 devices. Is there a way to achieve it?

1 Answer 1

5

It would be really convenient if you transform the above complex JSON into a collection that has one element per resource you want to create. To achieve this, you could use the flatten function.

locals {
  # A list of objects with one object per instance.
  flattened_values = flatten([
    for ip_key, ip in var.Bigip_devices : [
      for index in range(ip.bigip_instance_count) : {
        region  = ip.region
        azs            = ip.azs
        ip_index      = index
        ip_key        = ip_key
        cluster         = ip.cluster
        version        = ip.version
        sku   = ip.sku
        offer = ip.offer
        instance_type = ip.instance_type
        disable_password_authentication = ip.disable_password_authentication
        tags = ip.tags
      }
    ]
  ])
}

With the above flattened function, you get below list of collection of resources, you would like to create.

flattened_value_output = [
  {
    "azs" = [
      "1",
    ]
    "cluster" = "yes"
    "disable_password_authentication" = ""
    "instance_type" = ""
    "ip_index" = 0
    "ip_key" = "main_hub"
    "offer" = ""
    "region" = "eastus"
    "sku" = ""
    "tags" = ""
    "version" = ""
  },
  {
    "azs" = [
      "1",
    ]
    "cluster" = "yes"
    "disable_password_authentication" = ""
    "instance_type" = ""
    "ip_index" = 1
    "ip_key" = "main_hub"
    "offer" = ""
    "region" = "eastus"
    "sku" = ""
    "tags" = ""
    "version" = ""
  },
  {
    "azs" = [
      "1",
      "2",
    ]
    "cluster" = "yes"
    "disable_password_authentication" = ""
    "instance_type" = ""
    "ip_index" = 0
    "ip_key" = "spoke"
    "offer" = ""
    "region" = "eastus"
    "sku" = ""
    "tags" = ""
    "version" = ""
  },
  {
    "azs" = [
      "1",
      "2",
    ]
    "cluster" = "yes"
    "disable_password_authentication" = ""
    "instance_type" = ""
    "ip_index" = 1
    "ip_key" = "spoke"
    "offer" = ""
    "region" = "eastus"
    "sku" = ""
    "tags" = ""
    "version" = ""
  },
  {
    "azs" = [
      "1",
      "2",
    ]
    "cluster" = "yes"
    "disable_password_authentication" = ""
    "instance_type" = ""
    "ip_index" = 2
    "ip_key" = "spoke"
    "offer" = ""
    "region" = "eastus"
    "sku" = ""
    "tags" = ""
    "version" = ""
  },
  {
    "azs" = [
      "1",
      "2",
    ]
    "cluster" = "yes"
    "disable_password_authentication" = ""
    "instance_type" = ""
    "ip_index" = 3
    "ip_key" = "spoke"
    "offer" = ""
    "region" = "eastus"
    "sku" = ""
    "tags" = ""
    "version" = ""
  },
]

From the above collection, you could iterate & create resources with unique keys like below::

resource "some_resource" "example" {
  for_each = {
    # Generate a unique string identifier for each instance
    for ip in local.flattened_value_output : format("%s-%02d", ip.ip_key, ip.ip_index + 1) => ip
  }
}

This way, the creation or updating of resources is guaranteed as each resource uses a unique key.

For more details, refer this discussion I had with Hashicorp personnel.

Sign up to request clarification or add additional context in comments.

1 Comment

Awesome solution! Thanks, works like a charm. The example and the explanation is great as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.