Hi there, I have a problem passing variable type list from a module to another module, it is compose with the output from another module.
Example:
./tfmodules/vpc/main.tf
...
output "public_subnet_1_id" {
value = "${aws_subnet.sn_public_1.id}"
}
output "private_subnet_2_id" {
value = "${aws_subnet.sn_private_2.id}"
}
...
./tfmodules/elb/main.tf
...
resource "aws_elb" "my_elb" {
name = "myelb"
# Public subnets
subnets = "${var.public_subnets}"
}
variable "public_subnets" {
type = "list"
description = "Subnets available"
}
...
./main.tf
module "elb" {
source = "./tfmodules/elb/"
public_subnets = ["${module.vpc.public_subnet_1_id}", "${module.vpc.public_subnet_2_id}"]
}
I have got the follow error:
$ terraform plan
1 error(s) occurred:
* module.elb.aws_elb.my_elb: subnets: should be a list
But is worked if I put with this way:
./main.tf
module "elb" {
source = "./tfmodules/elb/"
public_subnets = ["subnet-ab978fcf", "subnet-ecabb39a"]
}
v0.9.1
See above
See above
Catch the two values to compose the variable of type list
module.elb.aws_elb.my_elb: subnets: should be a list
See above
Hi @mario21ic, thanks for the issue!
If you use the interpolation function list()
do you still get the parse error?
module "elb" {
source = "./tfmodules/elb/"
public_subnets = "${list("${module.vpc.public_subnet_1_id}", "${module.vpc.public_subnet_2_id}")}"
}
Hello @grubernaut, thanks for the answer, but, yes I still giving the same error, I followed the guide https://www.terraform.io/docs/configuration/interpolation.html
Using list()
allows TF to parse for me locally with TF 0.9.2.
$ cat main.tf
variable "foo" { default = "bar" }
variable "bar" { default = "foo" }
module "mod" {
source = "./mod"
lists = "${list("${var.foo}", "${var.bar}")}"
}
output "foofoo" { value = "${module.mod.foo}"}
$ cat mod/main.tf
variable "lists" {
type = "list"
description = "list var"
}
output "foo" { value = "${var.lists}" }
$ terraform apply
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
foofoo = [
bar,
foo
]
I'll try setting the input variables to the list()
interpolation function next and see if I can reproduce.
Hello @grubernaut , thanks for the attention, the case is uploaded in https://github.com/mario21ic/terraform-aws-vpc-elb/blob/master/main.tf#L32
Hey folks - we ran into this same issue in one of our configs.
I cooked up a minimal repro case here before I found this issue - it looks very similar to @mario21ic's description:
https://github.com/phinze/terraform-issues/tree/master/should-be-a-list
In my experimentation it seems that the key bit is that the output of the module generating the list needs to be computed. See the README
in the link for detailed repro steps.
@mario21ic try to add [] in resource
./tfmodules/elb/main.tf
resource "aws_elb" "my_elb" {
name = "myelb"
# Public subnets
subnets = ["${var.public_subnets}"]
}
Hi :-)
Any updates about this issue ?
I have the following code :
data "terraform_remote_state" "vpc_rs" {
backend = "s3"
config {
bucket = "${var.vpc_rs_bucket}"
key = "${var.vpc_rs_key}"
region = "${var.region}"
}
}
module "asg" {
source = "../modules/asg/"
owner = "${var.owner}"
lc_name = "test"
lc_ssh_key_name = "${var.ssh_key_name}"
asg_name = "test asg"
asg_max_size = "1"
asg_min_size = "1"
asg_desired_capacity = "1"
asg_vpc_zone_identifier = ["${split( ",", data.terraform_remote_state.vpc_rs.private_subnet)}"]
}
output "test_list" {
value = "${split( ",", data.terraform_remote_state.vpc_rs.private_subnet)}"
}
During a plan or a validate I got the following error :
terraform validate
There are warnings and/or errors related to your configuration. Please
fix these before continuing.
Errors:
* module.asg.aws_autoscaling_group.mod_asg: vpc_zone_identifier: should be a list
If I comment the module bit I got following in the output :
terraform apply
data.terraform_remote_state.vpc_rs: Refreshing state...
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
region = eu-west-1
test_list = [
subnet-f1c38ab8,
subnet-ba69eae1,
subnet-741f5913
]
Did I do something wrong ?
Edit : Actually I did, it's now working. Sorry for the noise.
@renaudhager what did you do wrong that code? I am getting a similar issue!!!
@samof76 I've fixed similar issue. When you pass this list to resource inside module you have to wrap it in square brackets again, eg:
# module/main.tf
variable "list_sg" {
type = "list"
}
varaible "list_subnets" {
type = "list"
}
resource "aws_smthing" "example" {
...
security_group_ids = ["${var.list_sg}"] # won't work without brackets
subnet_ids = ["${var.list_subnets}"]
...
}
# example.tf
module "example" {
source "./module"
list_sg = [
"${data.data.terraform_remote_state.security_group_1}",
"${data.data.terraform_remote_state.security_group_2}"
]
list_subnets = ["${split(",",data.terraform_remote_state.subnets)}"]
}
I can confirm that the workaround suggested by @ayarmoluk17 works as expected (with terraform 0.11.0). Is this the idiomatic solution, or a workaround based on another bug, or something in between? Will the code like that will continue to work after this bug (or some other bug) is fixed?
Having the same issue. Seems to stem from constructing a list from the outputs of another module.
I have encountered this issue (unsurprisingly when trying to pass around lists of subnets also)
I was using version 0.11.2
.
While the workaround put forward by @ayarmoluk17 seems to "work" its got a bit of an annoying caveat.
For example, when I use it in an ASG:
resource "aws_autoscaling_group" "foo_asg" {
...
vpc_zone_identifier = ["${var.subnets}"]
...
}
I get something like this in the plan
output:
+ module.ec2.aws_autoscaling_group.foo_asg
...
vpc_zone_identifier.#: "1"
vpc_zone_identifier.620245603: "subnet1,subnet2,subnet3"
...
As you can see Terraform has produced a list with one element, that element being the comma separated list as a string.
This ends up working well and good, it looks like somewhere (I'm guessing on the AWS end) it gets "corrected".
The problem is when you then run the next plan/apply
:
Terraform will perform the following actions:
~ module.ec2.aws_autoscaling_group.foo_asg
...
vpc_zone_identifier.#: "3" => "1"
vpc_zone_identifier.2085961902: "subnet1" => ""
vpc_zone_identifier.2697889770: "subnet2" => ""
vpc_zone_identifier.620245603: "" => "subnet1,subnet2,subnet3"
vpc_zone_identifier.649183968: "subnet3" => ""
...
This will happen every time plan/apply
is called even though there is really no change.
Other than the niggle that there are changes and (identity) actions that are taken each time
when there are no changes, this causes an actual blocker when this list of subnets is used in
something like an ALB:
resource "aws_alb" "foo-alb" {
...
subnets = ["${var.subnets}"]
...
}
Again the plan for this looks like the following:
+ module.ec2.aws_alb.foo-alb
...
subnets.#: "1"
subnets.620245603: "subnet1,subnet2,subnet3"
...
Unfortunately while it was workable in the ASG case, attempting to apply this plan results in the following error:
* aws_alb.foo-alb: Error creating Application Load Balancer: ValidationError: At least two subnets in two different Availability Zones must be specified
status code: 400, request id: ****
I might also just point out that the 3 subnets were indeed in different availability zones, so it should have worked.
I believe its complaining because the list submitted in the request only had 1 element.
To work around this issue, I thought "oh, its interpreting the list as a comma separated string, so hopefully I just need to replace var.subnets
with
split(",", var.subnets)
. Unfortunately this did not work, it had a runtime type error because the second input to split
is required to be a string
while var.subnets
is of type list. At this point I'm actually getting confused which it is myself.
Anyway what did eventually work for me was ["${split(",", join(",", var.subnets))}"]
. So I had to turn the list into a comma separated string,
then I had to split it back out again.
So:
ASG:
resource "aws_autoscaling_group" "foo_asg" {
...
vpc_zone_identifier = ["${split(",", join(",", var.subnets))}"]
...
}
ALB:
resource "aws_alb" "foo-alb" {
...
subnets = ["${split(",", join(",", var.subnets))}"]
...
}
Both have the desired plans:
+ module.ec2.aws_autoscaling_group.foo_asg
...
vpc_zone_identifier.#: "3"
vpc_zone_identifier.2085961902: "subnet1"
vpc_zone_identifier.2697889770: "subnet2"
vpc_zone_identifier.649183968: "subnet3"
...
+ module.ec2.aws_alb.foo-alb
...
subnets.#: "3"
subnets.2085961902: "subnet1"
subnets.2697889770: "subnet2"
subnets.649183968: "subnet3"
...
And applying the plan works, the ALB is successfully created.
The join
and then split
is obviously not ideal. I spose I could join
the list before i pass it into
the module, and split it inside the module to make it look (only slightly) prettier, but then again I'd rather have more ugliness localised together
to make the refactoring easier when the problem is eventually fixed.
We have a similar issue with a slight variation (?) from above:
Faced the same issue when trying to pass around list of objects (maps) such as those for the connection_string property on the Azure App Service:
locals {
db_connectionstring = {
name = "DB"
type = "SQLAzure"
value = "${format("%s;Initial Catalog=%s", module.data-common.sqlserver-connectionstring, module.db.instance["name"])}"
}
}
and later:
module "appservice" {
source = "../modules/appservices"
...
connections = "${list(local.db_connectionstring)}"
}
always gives the error: connection_string should be a list
When trying the workaround with the brackets in the referenced App Service module it will show an error that the properties are not properly set for the connection_string input object (connection_string.0.name, connection_string.0.type, connection_string.0.value).
So looks like the workaround is not valid for list of objects...
Hi all,
Although we've not directly verified this one yet, I strongly suspect it will be fixed by the improved language interpreter coming in the next major release. Although it's not directly one of the line items in that article, the changes made to support things like rich types in module inputs and outputs have improved the robustness of how Terraform thinks about complex types (types constructed from other types, like lists), including allowing it to represent "unknown-ness" without losing track of the fact that the value is a list, which is the root cause of the bug here.
I've updated the labels here to remind us to look at this issue again when we're doing pre-release testing.
@appelgriebsch I have the Connection string values working in Azure using Variables
connection_string = [{
name = "ConnectionString"
type = "SQLAzure"
value = "Data Source=tcp:${var.sql_server_name}.database.windows.net,1433;Initial Catalog=${var.mssql_database_name};User ID=${var.sql_server_login_name};Password=${var.sql_server_admin_password}"
}]
@whytoe yes, that will still work and I use this way for scenarios I have the required information for the connection string in my var-file anyway... but for connection strings to e.g. CosmosDB, ServiceBus, Storage Account, etcpp. I will need access keys that are not available upfront and so I have to refer to output from another tf module...
@appelgriebsch ya for sure, I just saw the app_service example and thought I would try and help you out in the interim
Hi all! Sorry for the long silence here.
This issue is covering the same root cause as #12263, which I've closed today since it appears to be fixed in v0.12.0-alpha1. We do still have issue #19140 open related to the problem of updating the common workaround of wrapping an extra level of list brackets around the expression, which we'll aim to address separately before v0.12.0 final.
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.
Most helpful comment
@samof76 I've fixed similar issue. When you pass this list to resource inside module you have to wrap it in square brackets again, eg: