Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: length of "splat variable" should not be computed #14677

Closed
ashb opened this issue May 19, 2017 · 8 comments
Closed

core: length of "splat variable" should not be computed #14677

ashb opened this issue May 19, 2017 · 8 comments

Comments

@ashb
Copy link
Contributor

ashb commented May 19, 2017

I found a case that I would have expected to be fixed by #1497 but that still gives me the same sort of error. It's this below (using the terraform-community-modules tf_aws_vpc and (my fork) of the tf_aws_nat modules):

Thinking a bit more about this I can see why its coming up as computed. The flow is as follows:

  • use data source to get current AZs
  • this is variable is used in a ${slice()} interpolation as the input variable to a module
  • this gets fed into count = "${length(var.public_subnets)}" inside the module
  • The aws_subnet resource with this count uses a splat in the output output "public_subnets" { value = ["${aws_subnet.public.*.id}"] }
  • I then try using the the calling ${length(mod.vpc.public_subnets)}

So I can make the inference between the count and aws_subnet.public.*.id but it's probably one level of indirection too much

Terraform v0.9.5, running terraform plan I get:

data.aws_availability_zones.available: Refreshing state...
data.aws_region.current: Refreshing state...
data.aws_ami.ami: Refreshing state...
Error refreshing state: 1 error(s) occurred:

* module.nat.data.aws_subnet.subnets: data.aws_subnet.subnets: value of 'count' cannot be computed

The terraform code I'm using is:

data "aws_availability_zones" "available" {}
variable "cidr" { default = "10.123.0.0/16" }
module "vpc" {
  source = "github.com/terraform-community-modules/tf_aws_vpc?ref=v1.0.4"
  name = "my-vpc"

  enable_dns_hostnames = true
  enable_dns_support = true

  azs = "${data.aws_availability_zones.available.names}"
  cidr = "${var.cidr}"

  private_subnets = [ "${
    slice(list(
      cidrsubnet(var.cidr, 8, 0),
      cidrsubnet(var.cidr, 8, 1),
      cidrsubnet(var.cidr, 8, 2),
      cidrsubnet(var.cidr, 8, 3),
      cidrsubnet(var.cidr, 8, 4),
    ), 0, length(data.aws_availability_zones.available.names))
  }" ]
  public_subnets = [ "${
    slice(list(
      cidrsubnet(var.cidr, 8, 100),
      cidrsubnet(var.cidr, 8, 101),
      cidrsubnet(var.cidr, 8, 102),
      cidrsubnet(var.cidr, 8, 103),
      cidrsubnet(var.cidr, 8, 104),
    ), 0, length(data.aws_availability_zones.available.names))
  }" ]
}

module "nat" {
  source                 = "github.com/ashb/tf_aws_nat?ref=43f7249"
  name                   = "my-nat"
  instance_count         = 1
  instance_type          = "t2.micro"
  subnet_ids      = ["${module.vpc.public_subnets}"]
  az_list                = ["${module.vpc.public_subnets}"]
  vpc_security_group_ids = []
  aws_key_name           = ""
}
@apparentlymart
Copy link
Contributor

Hi @ashb! Thanks for following up with this extra detail.

If I'm understanding correctly, I think the way this violated your expectations is that even though the values of the list are computed, Terraform should know the length of the list, because that's derived from a variable.

If so, then I agree: Terraform ought to be able to figure this out in an ideal world. Right now this information doesn't thread through properly because there is a rule that if a list contains any unknown values then it becomes entirely unknown when returned from an interpolation sequence; this is a limitation we've inherited from Terraform's core architecture, and so not something we can fix quickly.

I think is is something we should be able to resolve as part of some holistic work we're hoping to do soon to improve consistency how Terraform passes values around. This should allow us to preserve details like "unknown" properly as they thread between different subsystems. That work is still in the early planning/prototyping phase right now, so I can't say for sure, but we'll keep this issue here for now and update when there's something more concrete and definite to say here.

Thanks again for filing this!

@apparentlymart apparentlymart changed the title value of 'count' cannot be computed, but it is static-ish. core: length of "splat variable" should not be computed May 19, 2017
@ashb
Copy link
Contributor Author

ashb commented May 19, 2017

Terraform should know the length of the list, because that's derived from a variable.

Yeah, that was why I was somewhat surprised that it didn't work, but when I wrote it all out in detail I realised why it wasn't working right now.

In my case the work around was easy enough (just create a count variable to the module and call length(data.aws_availability_zones.available.names) myself).

@b-dean
Copy link

b-dean commented Sep 12, 2017

Terraform should know the length of the list, because that's derived from a variable.

@apparentlymart, I would go a step further and say Terraform should know the length of the list if it is a fixed length, even if every value is computed.

I've been looking around at the many variations on this issue and I certainly see that many times the length of the list is computed so it can't be known at plan time. I think there are times where the length of the list is fixed, but the values are computed. So the length isn't even from a variable, there's just two items, but they have computed values so terraform somehow doesn't know how many items are in the list. Example:

resource "aws_iam_policy" "foo" { }
resource "aws_iam_policy" "bar" { }
module "baz" {
  iam_policies = [
    "${aws_iam_policy.foo.arn}",
    "${aws_iam_policy.bar.arn}",
  ]
}

# then in the module
variable "iam_policies" {
  type = "list"
  default = []
}

resource "aws_iam_role_policy_attachment" "policy" {
  policy_arn = "${var.iam_policies[count.index]}"
  role = "${aws_iam_role.foo.name}"
  count = "${length(var.iam_policies)}"
}

The workaround is to just pass in the length in another variable, since I know what it is right there where I'm setting the value of the list. But that seems kinda silly.

module "baz" {
  iam_policies = [
    "${aws_iam_policy.foo.arn}",
    "${aws_iam_policy.bar.arn}",
  ]
  iam_policy_count = 2
}

Or the two-pass plan where I do an apply to make the policies and then the plan that passes them into the module. No matter what I pick it seems like a hack

@oprinmarius
Copy link

oprinmarius commented Mar 22, 2018

I am running into the same problem while trying to create aws_ssm_parameters by passing it a map.

I have a map with fixed number of keys, but their values are coming from module outputs or other resources.
I am then passing this map to the SSM_parameters module and try to create the parameters in the following way :

locals {
   ssm_map = {
      DB_NAME = "wordpress"
      DB_USERNAME = "wordpress-user"
      DB_PASSWORD = "${random_string.rds_password.result}"
      DB_HOSTNAME = "${module.rds_instance.hostname}"
   }
}

module "ssm_parameters" {
  source    = ....
  ssm_map = "${local.ssm_map}"
  ...
}


....
# ssm_parameter module

resource "aws_ssm_parameter" "configs" {
  count  = "${length(keys(var.ssm_map))}"
  ...
}

When I am trying to use. count = ${length(keys(var.ssm_map))} I get value of 'count' cannot be computed even though I have a fixed number of keys with specific names. Only the values of the keys are computed.

The workaround is to pass another variable ssm_count = 4 but this doesn't feel right at all.

vancluever added a commit to hashicorp/terraform-provider-vsphere that referenced this issue May 10, 2018
This contains the full CRUD/tests/docs for the
vsphere_datastore_cluster_vm_anti_affinity_rule resource.

One thing to note here - during testing, it was found that a
virtual_machine_ids length of less than 2 is essentially a no-op on the
cluster, resulting in no rules created. This was causing issues where
the apply was succeeding but not rule was being returned, resulting in
odd errors post-creation. In addition to this, we cannot restrict this
with MinItems, as there currently seems to be an issue calculating the
length of a glob of computed values - ie:
vsphere_virtual_machine.vm.*.id, even when the count in
vsphere_virtual_machine is static.

If I'm assuming correctly, this is because when the computed/unknown
value is seen, the entire field becomes unknown with a length of 1,
regardless of if the final length is known beforehand.

Further reading can be found at:
hashicorp/terraform#14677 (comment)
vancluever added a commit to hashicorp/terraform-provider-vsphere that referenced this issue May 10, 2018
This contains the full CRUD/tests/docs for the
vsphere_datastore_cluster_vm_anti_affinity_rule resource.

One thing to note here - during testing, it was found that a
virtual_machine_ids length of less than 2 is essentially a no-op on the
cluster, resulting in no rules created. This was causing issues where
the apply was succeeding but no rule was being returned, resulting in
odd errors post-creation. In addition to this, we cannot restrict this
with MinItems, as there currently seems to be an issue calculating the
length of a glob of computed values - ie:
vsphere_virtual_machine.vm.*.id, even when the count in
vsphere_virtual_machine is static.

If I'm assuming correctly, this is because when the computed/unknown
value is seen, the entire field becomes unknown with a length of 1,
regardless of if the final length is known beforehand.

Further reading can be found at:
hashicorp/terraform#14677 (comment)
vancluever added a commit to hashicorp/terraform-provider-vsphere that referenced this issue May 11, 2018
This contains the full CRUD/tests/docs for the
vsphere_datastore_cluster_vm_anti_affinity_rule resource.

One thing to note here - during testing, it was found that a
virtual_machine_ids length of less than 2 is essentially a no-op on the
cluster, resulting in no rules created. This was causing issues where
the apply was succeeding but no rule was being returned, resulting in
odd errors post-creation. In addition to this, we cannot restrict this
with MinItems, as there currently seems to be an issue calculating the
length of a glob of computed values - ie:
vsphere_virtual_machine.vm.*.id, even when the count in
vsphere_virtual_machine is static.

If I'm assuming correctly, this is because when the computed/unknown
value is seen, the entire field becomes unknown with a length of 1,
regardless of if the final length is known beforehand.

Further reading can be found at:
hashicorp/terraform#14677 (comment)
bill-rich pushed a commit to hashicorp/terraform-provider-vsphere that referenced this issue Jul 13, 2018
This contains the full CRUD/tests/docs for the
vsphere_datastore_cluster_vm_anti_affinity_rule resource.

One thing to note here - during testing, it was found that a
virtual_machine_ids length of less than 2 is essentially a no-op on the
cluster, resulting in no rules created. This was causing issues where
the apply was succeeding but no rule was being returned, resulting in
odd errors post-creation. In addition to this, we cannot restrict this
with MinItems, as there currently seems to be an issue calculating the
length of a glob of computed values - ie:
vsphere_virtual_machine.vm.*.id, even when the count in
vsphere_virtual_machine is static.

If I'm assuming correctly, this is because when the computed/unknown
value is seen, the entire field becomes unknown with a length of 1,
regardless of if the final length is known beforehand.

Further reading can be found at:
hashicorp/terraform#14677 (comment)
@seanjfellows
Copy link

@mildwonkey I don't really understand why 10857 was closed and merged into this one, considering that 10857 is more than a year older than this issue and has >5x the participants. Relatedly, I never got a reply to my question at #10857 (comment)

@seanjfellows
Copy link

Oh nevermind, it looks like #12570 has a lot of discussion on it (I think the two issues linked from #10857 (comment) actually have less conversation than that one)

@apparentlymart
Copy link
Contributor

Hi all! Over in #10857 is a broader discussion about computed counts, but my latest comment includes my verification that the particular bug reported by this issue has been fixed in Terraform v0.12.0-alpha1.

What fixed this is a removal of the rule that a known list may not contain a computed (now called "unknown") value: the list remains known, and thus its length is known, and only accessing the specific unknown element directly will result in an unknown value.

This fix is already in master and will be included in the v0.12.0 final release, and so I'm going to close this out. Thanks for reporting this bug, and thanks also for your patience while we laid the groundwork to be able to resolve it.

@ghost
Copy link

ghost commented Apr 1, 2020

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.

@ghost ghost locked and limited conversation to collaborators Apr 1, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants