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

Module output variables cannot be used to create a list input #16916

Closed
TheYorkshireDev opened this issue Dec 14, 2017 · 11 comments
Closed

Module output variables cannot be used to create a list input #16916

TheYorkshireDev opened this issue Dec 14, 2017 · 11 comments
Milestone

Comments

@TheYorkshireDev
Copy link

Hi all,

I cannot seem to pass through a list of strings when the strings are outputs of another module.

Terraform Version

Terraform v0.11.1

Terraform Configuration Files

Module Firewalls vars.tf:

variable "tags" {
  description = "List of tags to apply to the firewall"
  type        = "list"
}

Module Firewalls main.tf:

resource "digitalocean_firewall" "wall1" {
  name = "FIRE1"

  tags = "${var.tags}"

  ...
 }

root.tf

module "tags" {
  source = "./tags"
}

module "firewalls" {
  source = "./firewalls"
  tags     = ["${module.tags.firewall_tags}"]
}
  • Module tags has the output variable of firewall_tags which is type string
  • Module firewalls has the input variable tags which is of type List

Expected Behavior

Expected the ["${module.tags.firewall_tags}"] to be resolved as a string list

Actual Behavior

Error: module.firewalls.digitalocean_firewall.wall1: tags: should be a list

Steps to Reproduce

terraform plan

Important Factoids

I have found two instances where this behaviour does not appear and all is fine:

Hard-Coded List:root.tf

module "tags" {
  source = "./tags"
}

module "firewalls" {
  source = "./firewalls"
  tags     = ["HARDCODED"]
}

Using locals:root.tf

module "tags" {
  source = "./tags"
}
locals {
   temp = "LOCAL"
}
module "firewalls" {
  source = "./firewalls"
  tags     = ["${local.temp}"]
}
@jbardin
Copy link
Member

jbardin commented Dec 14, 2017

Hi @TheYorkshireDev,

Can you show the configuration that's generating the module.tags.firewall_tags list? A simple hard-coded output works as expected, but there are still some edge cases where type information is list between modules.

I'm not sure if it effects the results you see, but you don't want the square brackets around "${module.tags.firewall_tags}" if that is already a list.

@jbardin jbardin added the waiting-response An issue/pull request is waiting for a response from the community label Dec 14, 2017
@TheYorkshireDev
Copy link
Author

@jbardin I checked the state file and it was just as string, but here is the config.

Module.Tags main.tf

resource "digitalocean_tag" "firewall" {
  name = "FIREWALL"
}

Module.Tags output.tf

output "firewall_tags" {
  value = "${digitalocean_tag.firewall.name}"
}

@jbardin
Copy link
Member

jbardin commented Dec 14, 2017

Ah, got it. Yes, it looks like when the value is computed, the fact the square brackets turned it into a list was lost.

@jbardin jbardin added bug config and removed waiting-response An issue/pull request is waiting for a response from the community labels Dec 14, 2017
@gvilarino
Copy link

Hi, same problem here. Any ETA on this? It's really a tough issue to identify, specially for newcomers like me 😅

vandrijevik added a commit to tablexi/terraform_modules that referenced this issue Aug 9, 2018
wking added a commit to wking/openshift-installer that referenced this issue Sep 12, 2018
This will make it easier to move into the existing infra step.

The module source syntax used in the README is documented in [1,2,3],
and means "the modules/aws/ami subdirectory of the
github.com/openshift/installer repository cloned over HTTPS", etc.

I don't think I should need the wrapping brackets in:

  vpc_security_group_ids = ["${var.vpc_security_group_ids}"]

but without it I get [4]:

  Error: module.bootstrap.aws_instance.bootstrap: vpc_security_group_ids: should be a list

The explicit brackets match our approach in the master and worker
modules though, so they shouldn't break anything.  It sounds like
Terraform still has a few problems with remembering type information
[5], and that may be what's going on here.

I've simplified the tagging a bit, keeping the extra tags unification
outside the module.  I tried dropping the kubernetes.io/cluster/ tag
completely, but it lead to [6]:

  Sep 12 05:08:08 ip-10-0-6-58 hyperkube[4122]: E0912 05:08:08.075211    4122 tags.go:94] Tag "KubernetesCluster" nor "kubernetes.io/cluster/..." not found; Kubernetes may behave unexpectedly.
  Sep 12 05:08:08 ip-10-0-6-58 hyperkube[4122]: F0912 05:08:08.075258    4122 server.go:262] failed to run Kubelet: could not init cloud provider "aws": AWS cloud failed to find ClusterID

The backing code for that is [7,8,9].  From [9], you can see that only
the tag on the instance matters, so I've dropped
kubernetes.io/cluster/... from volume_tags.  Going forward, we may
move to configuring this directly instead of relying on the tag-based
initialization.

[1]: https://www.terraform.io/docs/configuration/modules.html#source
[2]: https://www.terraform.io/docs/modules/sources.html#github
[3]: https://www.terraform.io/docs/modules/sources.html#modules-in-package-sub-directories
[4]: https://storage.googleapis.com/origin-ci-test/pr-logs/pull/openshift_installer/217/pull-ci-openshift-installer-e2e-aws/47/build-log.txt
[5]: hashicorp/terraform#16916 (comment)
[6]: openshift#217
[7]: https://github.com/kubernetes/kubernetes/blob/v1.11.3/pkg/cloudprovider/providers/aws/tags.go#L30-L34
[8]: https://github.com/kubernetes/kubernetes/blob/v1.11.3/pkg/cloudprovider/providers/aws/tags.go#L100-L126
[9]: https://github.com/kubernetes/kubernetes/blob/v1.11.3/pkg/cloudprovider/providers/aws/aws.go#L1126-L1132
@jspenc72
Copy link

Is there a workaround for this?

@neg3ntropy
Copy link

@jspenc72 csv: join and split everywhere.

@jspenc72
Copy link

jspenc72 commented Oct 3, 2018

@soulrebel can you post an example?

@jaceq
Copy link

jaceq commented Oct 4, 2018

I have same issue with list of maps (@soulrebel and join won't work in my case)...
I try to pass to module something like that:

#                               {
#                                 name = "store.host"
#                                value = "${google_redis_instance.search.host}"
#                               },
                               {
                                 name = "store.port"
                                 value = "${var.store_port}"
                               },
                               {
                                 name = "HOST2"
                                 value = "http://${var.host2}/de"
                               },
                               {
                                 name = "HOST1"
                                 value = "http://${var.host1_name}:8983/"
                               }
                             ]

In module I have:

env = "${var.env_var}"

Basically when I hashout (as it is hashed out on example above) the map which contains output from another module and pass data containing only strings or variables then it works, other wise I get:

spec.0.template.0.spec.0.container.0.env: should be a list

@rpatrick00
Copy link

rpatrick00 commented Oct 17, 2018

This issue really makes the value of modules very limited. For example, if I create an AWS VPC with subnets in one module and then need to pass the subnet IDs into the module to create my EKS cluster, you can only do it if you hardcode the number of subnets and pass each in a separate output variable.

It seems that passing an output as a list that is used as input to another module works fine if the list is all hard-coded strings. As soon as you try to use interpolation syntax--even for the individual list items--it no longer works. For example, assume you have some code that looks similar to this:

In module A:
output "foo" {
...
}

In module B:
variable "bar" {
type = "list"
}

resource "aws_eks_cluster" "mycluster" {
....
vpc_config {
subnet_ids = "${var.bar}"
}
}

In main code:

module "A" {
...
}

module "B" {
...
bar = "${module.A.foo}"
}

If the output foo is defined like this (which clearly doesn't help), the code above works as expected:

output "foo" {
value = [ "subnet-12345678", "subnet-23456789", "subnet-34567890" ]
}

If if the output foo is defined using interpolation syntax like either of the two examples below, you get the "should be a list" error.

output "foo" {
value = [ "${aws_subnet.subnet-1.id}", "${aws_subnet.subnet-2.id}", "${aws_subnet.subnet-3.id}" ]
}

or:

output "foo" {
value = "${list("${aws_subnet.subnet-1.id}", "${aws_subnet.subnet-2.id}", "${aws_subnet.subnet-3.id}")}"
}

I ended up having to abandon the use of well-defined modules for any situation where I need to pass lists of things as outputs that need to be used as inputs to other modules.

I tried the join/split workaround but was unable to get that to work properly either.

@apparentlymart
Copy link
Contributor

Hi all! Sorry for the long silence here.

This issue has the same root cause as #12263, which has now been fixed in master ready for inclusion in the forthcoming v0.12.0 release. Thanks for reporting it, and thanks for your patience while we figured out what was going on.

@apparentlymart apparentlymart added this to the v0.12.0 milestone Oct 30, 2018
@ghost
Copy link

ghost commented Mar 31, 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 Mar 31, 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

8 participants