Terraform: Can't use variables in module: aws_elb.classic_elb: instances: should be a list

Created on 24 Aug 2017  ยท  10Comments  ยท  Source: hashicorp/terraform

Terraform Version

$ terraform  -v
Terraform v0.10.2
$ uname -mprs
Darwin 15.6.0 x86_64 i386



md5-eec4efed2d976700e9fa5b4ed05bb5f2



module "instance_0" {
    source                      = "modules/generic_aws_instance"
    access_key                  = "${var.access_key}"
  ...
# Instance-related variables like chef/jenkins data passed here
}

module "instance_1" {
    source                      = "modules/generic_aws_instance"
    access_key                  = "${var.access_key}"
  ...
# Instance-related variables like chef/jenkins data passed here
}



md5-e1af1e14c752892f0c21d495e511fc32



output "instance_0_instance_id" {
    value = "<some description>: ${module.instance_0.instance_id}"
}

output "instance_1_instance_id" {
    value = "<some description>: ${module.instance_1.instance_id}"
}



md5-b1fa5a77a49f0aaecca2c387840385dd



module "test_elb" {
    source              = "modules/elb"
    access_key          = "${var.access_key}"
    secret_key          = "${var.secret_key}"
   ...
    instances           = [
                          "${module.instance_0.instance_id}"
                           "${module.instance_1.instance_id}"
                          ]
    tags                = "${var.platform_elb_tags}"
}

#                           "${module.platform_0.instance_id}"



md5-bbc0a70520872f578ff87697dc01c5c2



    instances           = [
                          "i-1234567890"
                           "i-0987654321"
                          ]



md5-6c77038b4c07626c220f9f0bf783f0a4



module "security_group_rules_mysql_slave" {
    source              = "modules/edit_security_group_rules"
...
    open_ports          = "${var.mysql_open_ports}"
    cidr_blocks         = [
                           "${module.instance_0.instance_public_ip/var.default_netmask}",
                           "${module.instance_0.instance_private_ip/var.default_netmask}",
                           "${module.instance_1.instance_public_ip/var.default_netmask}",
                           "${module.instance_1.instance_private_ip/var.default_netmask}"
                          ]
}

From user's point of view it looks like same issue, described here
https://github.com/terraform-providers/terraform-provider-aws/issues/292

but I can't be 100% sure so created this issue.

bug config

All 10 comments

Hi @evgeniagusakova! Sorry for this strange behavior.

I'm not sure exactly what's causing this. It sounds from your description that you'd created both instances using -target before trying to create the ELB; is that correct?

A possible workaround is to construct the list dynamically using the list function, rather than using the list syntax as you did here:

  instances = "${list(module.instance_0.instance_id, module.instance_1.instance_id)}"

These two versions _should_ be equivalent, but I'm wondering if something strange is happening in the handling of the list here. Could you give this a try and let me know if the result changes at all?

If you _didn't_ separately create the instances before creating the ELB, it'd also be interesting to see if it helps to create these items in separate steps like this:

$ terraform apply -target=module.instance_0
$ terraform apply -target=module.instance_1
$ terraform apply -target=module.test_elb

I am wondering if the problem here is being caused by the module results being <computed> when attempting to create all of the resources at once; forcing Terraform to create just the instances alone first would help to determine if this is a <computed> value problem, or a more general problem.

Finally, if you _are_ able to run the first two apply steps above but you find that the third fails with the error you reported, it would be useful to see what happens if you evaluate the following expressions in the terraform console command at that point (each line is a separate expression to try):

module.instance_0.instance_id
module.instance_1.instance_id
list(module.instance_0.instance_id, module.instance_1.instance_id)

Sorry I don't have an immediate explanation/workaround here. It seems like you've found an edge-case here in the interaction between some components but I'm not sure yet which components are involved.


The rest of this comment is not directly about the problem you've reported here, but just something I noticed in your module "security_group_rules_mysql_slave" example.

For your cidr_blocks example, please note that the syntax you've used there is using / as the division operator rather than as a literal string separator for the CIDR block syntax. To get the literal / it would be necesary to write it like this:

  "${module.instance_0.instance_public_ip}/${var.default_netmask}"

Hi!

I'm not sure exactly what's causing this. It sounds from your description that you'd created both >>instances using -target before trying to create the ELB; is that correct?

yes, you are right, I created instances first with -target=.. before.
BTW, I did not found how to create all resources in one command, but anyway it is not an issue.

I have not included in issue explanation but I tried following workarounds:

1 - as you suggested:

  instances = "${list(module.instance_0.instance_id, module.instance_1.instance_id)}"

2 -move converting to list into module
(not sure about syntax, was it like "${var1}:${var2}" or "${var1:var2}", anyway I tested with test module output first, and output was OK)

  instances = "${module.instance_0.instance_id}:${module.instance_1.instance_id}"

And do split IN module

instances = "${split(":", var.instances)}"

Im both cases I got same result:

aws_elb.classic_elb: instances: should be a list

In console interpolation work as expected

terraform console 
>"${list(module.instance_0.instance_id, module.instance_1.instance_id)}"
[
  i-XXXX,
  i-YYYY
]

Also, if DO NOT create resources but just do output in module, list will be showed, and looks OK

So from my point of view it is related to _rendered_ resources.

Same symptoms for LB and Sec. rule: work with strings (static strings) but do not work with rendered variables from modules.

If you have fix/workaround I can test it (I did same for packer - built from branch and tested fix)
(to be honest this issue looks complicated for me, I have no ideas how to fix it)

Hi,

i also experienced similar problems with different resources:

  • aws_instance.vpc_security_group_ids
  • aws_cloudwatch_metric_alarm.{alarm_actions,ok_actions,insufficient_data_actions}

but with aws_cloudfront_distribution.aliases this kind of interpolation works without problems.

One working solution I found for aws_instance.vpc_security_group_ids is:

variable security_group_ids {
  type = "list"
}

resource "aws_instance" "instance" {
...
vpc_security_group_ids = ["${var.security_group_ids}"]
...
}

Maybe this works also with the other resources, which have this kind of error?

Exactly the same issue with GCP provider and ACL:

variable "service_accounts"  {
type = "map"
  default = {
    terraform-provisioning  = "some-email@ ... "
    qa                                    = "some-email@ ... "
...
}

# Need to build line like "READER:user-USER1, READER:user-USER1 ..."
# It is not possible to use count with google_storage_object_acl necause of race:
# Error 409: The metadata for object "SOME_OBJECT" was edited during the operation. 
# Please try again., conflict

data "template_file" "ca_readers" {
    template = "READER:user-$${joined_list}"
    vars {
        joined_list = "${join(",READER:user-", values(var.service_accounts))}"
    }
}

# Try to use list pre-creted list

resource "google_storage_object_acl" "ca_pem" {
    depends_on = [
        "null_resource.upload_ca_to_bucket"
    ]
    bucket = "${var.deployment_data}"
    object = "SOME_OBJECT"

    role_entity = "${list(split(",", data.template_file.ca_readers.rendered))}"
}

1 error(s) occurred:

* google_storage_object_acl.ca_pem: role_entity: should be a list

Hi all,

Coming back to this issue after some time, I see that this pattern actually emerged in a few other issues in the mean time and so I now have a better understanding of what's going on here:

Terraform's current expression evaluator has a rule that if a list contains a <computed> value then that gets "simplified" as the _entire list_ being <computed>, which was done to give more reasonable results if functions are applied to that result (since Terraform functions cannot deal with <computed> values themselves.)

Unfortunately in today's type system <computed> values are untyped, and so Terraform doesn't see that result as being a list, leading to this error.

The good news is that work is already underway to replace Terraform's expression evaluator with a new one that has more complete support for <computed> values and is able to retain their types, which should address this problem. The less-good news is that it's a fairly large project and so it'll take some time to get far enough that this particular problem is addressed, because lots of Terraform subsystems need to be updated before we can get the full benefit here.

In the mean time, I think the best workaround is the use of -target to create the dependent resources first so that there are not computed items in the list, which should then cause Terraform to see the result as a concrete list and thus not produce this error. I understand that this is an inconvenient workaround since it requires running Terraform in an unusual way and thus isn't useful in situations where Terraform is running in automation. Unfortunately so far I've not identified a workaround that can be expressed only within the configuration, due to how <computed> is currently handled. :confounded:

Hi @apparentlymart, thank you for the thorough explanation of what's going on. Is there any known workaround for data sources? I have something like

data "aws_sns_topic" "foo" {
  name = "foo"
}
module "somemodule" {
  source = "gabro/somemodule/aws"
  some_list = ["${data.aws_sns_topic.foo.arn}"]

I've tried refreshing the state of the data source using terraform -target data.aws_sns_topic.foo but whenever I run terraform apply I hit on "some_list: should be a list".

Found this issue after having problems trying to put computed values in a list of maps. Are there any updates/specific issues to track regarding the improvement you mentioned @apparentlymart?

Will try the -target workaround

While -target workaround works, it is not ideal. Is there update on this issue? Any idea when it might be fixed?

Hi all! Sorry for the long silence here.

This issue has the same root cause as #12263, which has now been addressed in master and included in v0.12.0-alpha1. It'll also be included in the v0.12.0 final release.

Because of that, I'm going to close this out. Thanks for reporting this, and thanks for your patience while we figured out what was going on here.

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