user1451104
user1451104

Reputation: 153

Terraform dynamically loop over elements in a list and expand based on values

This is a bit hard to describe. So I have a map that looks like this after I've simplified it for clarity:

server_ip_configs = {
mgmt        = {
    ct      = "1"
    }
applicationgateway    = {
    ct      = "1"
    }
monitor     = {
    ct      = "1"
    }
app      = {
    ct      = "3"
    }
}

What I want to do is iterate over the map to create a flat list where elements are multiplied by the number of the ct property into a new flat list. So we end up with a list that looks a bit like this:

server_ip_configs_mapped = [
       {
        name      = "mgmt-1"
        }
       {
        name      = "applicationgateway-1"
        }
       {
        name      = "monitor-1"
        }
       {
        name      = "app-1"
        }
       {
        name      = "app-2"
        }
       {
        name      = "app-3"
        }

    ]

Creating a list of elements for each row explicitly by setting a variable is trivial:

data "null_data_source" "server_list_ip_configs" {
  count = lookup(var.server_ip_configs[var.server_role], "ct", 0)

  inputs = {
    name    =   "${var.server_role}-${count.index +1}"
  }
}

I can put this in a module and call multiple instances of the module and concat the results. But this is not a nice way to do it and not at all DRY. Am I right in thinking there is no other way of doing this in Terraform? Is it because terraform is essentially declarative and maybe I should declare a list with multiple instance in it rather than try and generate one? Using a for loop won't work because you cant use an integer to iterate over explicitly from what I can see. So no:

for i in 5 

Any answers to this welcome. Thanks.

Upvotes: 3

Views: 6763

Answers (2)

Helder Sepulveda
Helder Sepulveda

Reputation: 17664

Terraform 0.12 introduced for loops, you can do something like:

variable "server_ip_configs" {
  default = {
    mgmt               = { ct = "1" }
    applicationgateway = { ct = "1" }
    monitor            = { ct = "1" }
    app                = { ct = "3" }
  }
}

output "myout" {
  value = [for k, v in var.server_ip_configs : { "name" = join("-", [k, v.ct]) }]
}

Here the terraform output of that


terraform apply

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

myout = [
  {
    "name" = "app-3"
  },
  {
    "name" = "applicationgateway-1"
  },
  {
    "name" = "mgmt-1"
  },
  {
    "name" = "monitor-1"
  },
]

Upvotes: 0

Tyler
Tyler

Reputation: 501

@Helder came close, but I interpreted the request slightly different. Your intentions are to build the list based on the ct value, which looks like a count. This should be what you are looking for. Notice the use of range() to do what you were looking in regard to the for i in 5 statement.

variable "server_ip_configs" {
  default = {
    mgmt               = { ct = "1" }
    applicationgateway = { ct = "1" }
    monitor            = { ct = "1" }
    app                = { ct = "3" }
  }
}

locals {
  server_ip_configs_mapped = flatten([
    for server, count in var.server_ip_configs : [
      for i in range(count.ct) : {
        "name" = join("-", [server, i+1])
      }
    ]
  ])
}

output server_ip_configs_mapped { value = local.server_ip_configs_mapped }

Output:

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

server_ip_configs_mapped = [
  {
    "name" = "app-1"
  },
  {
    "name" = "app-2"
  },
  {
    "name" = "app-3"
  },
  {
    "name" = "applicationgateway-1"
  },
  {
    "name" = "mgmt-1"
  },
  {
    "name" = "monitor-1"
  },
]

Upvotes: 5

Related Questions