3
votes

I am trying to extract the values from map variable based on certain conditions as below :-

    Variables.tf File content
    variable "users" {
    type = "map"
    default = {
    "101" = "[email protected]"
    "102" = "[email protected]"
    "103" = "[email protected]"
    "104" = "[email protected]"
    "105" = "[email protected]"
    "106" = "[email protected]"
     }
   }

Below is my main.tf file

    module "instance" {
    instance_private_ip = ["11.12.13.x"]
    dns_map = ["y"]
    users = ["z"]
    }

    module "instance2" {
    instance_private_ip = ["11.12.14.a"]
    dns_map = ["b"]
    users = ["c"]
    }

The value x should be all even numbers in users variables like - 102, 104 and so on. The value y should be same as x The value z should be corresponding to x and y. The value a should be all even numbers in users variables like - 101, 103 and so on. The value b should be same as a The value c should be corresponding to a and b. Example as below

module "instance" {
    instance_private_ip = ["11.12.13.102", "11.12.13.104", "11.12.13.106"]
    dns_map = ["102","104","106"]
    users = ["[email protected]","[email protected]","[email protected]"]
    }
module "instance2" {
    instance_private_ip = ["11.12.14.101", "11.12.14.103", "11.12.14.105"]
    dns_map = ["101","103","105"]
    users = ["[email protected]","[email protected]","[email protected]"]
    }

I am trying with ${element(var.notebook[count.index])} but it will give me the username and not the left side variable.

Any help is appreciated

1
Is this Terraform 0.12?Matt Schuchard
@MattSchuchard Yes 0.12.16Arpit Gupta

1 Answers

4
votes

Terraform's for expressions are the answer to most problems involving transformation and filtering of collections, and I think that's true of this case too.

locals {
  odd_users = [
    for octet, email in var.users : {
      email               = email
      octet               = octet
      dns_map             = tostring(octet)
      instance_private_ip = cidrsubnet("11.12.14.0/24", octet)
    }
    if (octet % 2) == 1
  ]
  even_users = [
    for octet, email in var.users : {
      email               = email
      octet               = octet
      dns_map             = tostring(octet)
      instance_private_ip = cidrsubnet("11.12.13.0/24", octet)
    }
    if (octet % 2) == 0
  ]
}

module "instance" {
  source = "..."

  instance_private_ip = local.even_users[*].instance_private_ip
  dns_map             = local.even_users[*].dns_map
  users               = local.even_users[*].email
}

module "instance2" {
  source = "..."

  instance_private_ip = local.odd_users[*].instance_private_ip
  dns_map             = local.odd_users[*].dns_map
  users               = local.odd_users[*].email
}

In the above example, the two local values first filter and transform the list, each producing a list of objects describing the users. Then in the two module blocks I used splat expressions to turn that back into a flat lists of strings as you called for in your example,


Rather than defining three separate variables in your child module that all must have the same length and indices, I'd suggest reworking that interface to take a single list of objects instead. You can define a variable users in your child module like this:

variable "users" {
  type = list(object({
    email               = string
    dns_map             = string
    instance_private_ip = string
  }))
}

With it defined like that, you can just pass the local values directly in the module calls:

module "instance" {
  source = "..."

  users = local.even_users
}

module "instance2" {
  source = "..."

  users = local.odd_users
}

Your child module itself might then use splat expressions to again obtain flat lists of strings if that's what it needs, or it could use the list of objects directly, depending on what the child module is going to do with these lists.