Terraform: conditional expression unknown with inferred types

Created on 17 Jun 2019  ยท  6Comments  ยท  Source: hashicorp/terraform

Terraform Version

Terraform v0.12.1

Terraform Configuration Files

random.tf

variable "region" {
  type = "string"
}

variable "account" {
  type    = "string"
}

variable "public_subnets" {
  type = "map"

   default = {
    "us-east-1" = ["subnet-123456", "subnet-654321"]
  }
}

 variable "private_subnets" {
  type = "map"
  default = {
    "prod.ap-southeast-2" = ["subnet-132456", "subnet-654321"]
  }
}
resource "aws_ecs_service" "admin" {
  <OMITTED OUTPUT>
  network_configuration {
    subnets          = var.account == "prod" ? var.private_subnets["${var.account}.${var.region}"] : var.public_subnets["${var.account}.${var.region}"]
  }
  <OMITTED OUTPUT>
}

random.tfvars

env                 = "production"
account             = "prod"
region              = "us-east-1"

Debug Output

Expected Behavior

Terraform plan should return "No changes" if no real changes were made.

Actual Behavior

      ~ network_configuration {
          ~ subnets          = [
              - "subnet-123456",
              - "subnet-654321",
            ] -> (known after apply)
        }
    }

Steps to Reproduce

terraform init
terraform plan -var-file=random.tfvars

Thanks!

bug config

All 6 comments

Hi @voodoodror,

Thanks for filing the issue!

What I discovered so far, is that this appears to be somehow caused by the conversion of the conditional with lists to a set type in the resource config. Assigning the conditional to a list attribute directly works as expected, as does removing the conditional.

Hi @jbardin,

Thanks for uploading fix for this issue.

Unfortunately I can confirm that the problem still present in Terraform v0.12.4.

This is the terraform plan output using the exact configuration in original issue:

      ~ network_configuration {
            assign_public_ip = true
            security_groups  = [
                "sg-082aa19d861b1f3bf",
            ]
          ~ subnets          = [
              - "subnet-00528cb777b7e2435",
              - "subnet-0320b5d515b24e372",
            ] -> (known after apply)
        }

While trying to come up with a solution, I've tried converting the variable from map of lists to map of strings (using Terraform v0.12.4):

variable "public_subnets" {
  type = "map"

  default = {
    "dyaws.us-east-1"    = "subnet-AB,subnet-ABC,subnet-ABCD"
  }
}
resource "aws_ecs_service" "admin" {
  <OMITTED OUTPUT>
  network_configuration {
    subnets          = var.account == "prod" ? split(",", var.private_subnets["${var.account}.${var.region}"]) : split(",", var.public_subnets["${var.account}.${var.region}"])
  }
  <OMITTED OUTPUT>
}

terraform plan:

      ~ network_configuration {
            assign_public_ip = true
            security_groups  = [
                "sg-ABCDEF",
            ]
          ~ subnets          = [
              - "subnet-XXX",
              - "subnet-YYY",
              + "subnet-AB",
              + "subnet-ABC",
              + "subnet-ABCD",
            ]
        }

I can confirm that it works the same way I would expect it be, but it seems like a very clumsy workaround.

It can be clearly seen that there's an issue with map of lists variables.

Hi @voodoodror,

Thanks for the update. The original issue I found does seem to be fixed, but the result you're getting is the same for another reason.

The type of the map in your configuration is not precise, and due to a combination of the unknown final type of both maps, and the fact that one of the maps does not contain the possible key for evaluation, the expression result is unknown during plan.

Specifying the variable types fully will allow the expression to return a known type:

type = map(list(string))

I think we can still do better at handling the inferred situation though, and I'm going to repoen this as a slightly different issue.

Without explicit types, the inferred value of the variable here is:

cty.TupleVal([]cty.Value{cty.StringVal("subnet-132456"), cty.StringVal("subnet-654321")})

And if the key does not exist, the returned value is cty.DynamicVal. Because a Tuple and a DynamicVal value reduce to a DynamicPseudoType, the end result is unknown.

Hi @voodoodror,

Thanks for the update. The original issue I found does seem to be fixed, but the result you're getting is the same for another reason.

The type of the map in your configuration is not precise, and due to a combination of the unknown final type of both maps, and the fact that one of the maps does not contain the possible key for evaluation, the expression result is unknown during plan.

Specifying the variable types fully will allow the expression to return a known type:

type = map(list(string))

I think we can still do better at handling the inferred situation though, and I'm going to repoen this as a slightly different issue.

Many thanks @jbardin !

Now it definitely works as it should. I guess I somehow missed the documentation part that explains about declaring map of various types.

I'm going to lock this issue because it has been closed for _30 days_ โณ. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

Was this page helpful?
0 / 5 - 0 ratings