Module issue with string variable in subnet: passes validate, fails plan

2,353 views
Skip to first unread message

Monosij Dutta-Roy

unread,
May 27, 2019, 2:09:57 PM5/27/19
to Terraform

I am in the process of learning TF and going through some tutorials. Using version 0.12.

Fixed some of the issues of the tutorials running on older syntax, such as tag = {}, but stuck on this issue when now incorporating modules.

As shown below, terraform validate works, but terraform plan gives the following error:
BTW I also ran a terraform 0.12upgrade and it did not find anything.

+++++++++++++++++++++++++++++++++++++++++++++++++++
vagrant@vbUBUN:/space/infra.tf/demo-18b/dev$ terraform validate 
Success! The configuration is valid.

vagrant@vbUBUN:/space/infra.tf/demo-18b/dev$ terraform plan 
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

module.instances.data.aws_ami.ubuntu: Refreshing state...

------------------------------------------------------------------------

Error: Incorrect attribute value type

  on ../modules/instances/instance.tf line 38, in resource "aws_instance" "instance":
  38:   subnet_id = "${var.PUBLIC_SUBNETS[0]}"

Inappropriate value for attribute "subnet_id": string required.
+++++++++++++++++++++++++++++++++++++++++++++++++++

I changed the line to see if it would pass plan and it did.
subnet_id = "${var.PUBLIC_SUBNETS[0]}"
to 
subnet_id = "1.1.1.1"


Here is the snippet of code from my instance.tf being called from dev and prod modules

#-------------------------------------------------#
resource "aws_instance" "instance" {
  ami           = "${data.aws_ami.ubuntu.id}"
  instance_type = "${var.INSTANCE_TYPE}"

  # the VPC subnet
  subnet_id = "${var.PUBLIC_SUBNETS[0]}"

  # the security group
  vpc_security_group_ids = ["${aws_security_group.allow-ssh.id}"]

  # the public SSH key
  key_name = "${aws_key_pair.mykeypair.key_name}"

  tags = {
    Name         = "instance-${var.ENV}"
    Environmnent = "${var.ENV}"
  }
}
#-------------------------------------------------#

Thank you for your help.

Mono

Monosij Dutta-Roy

unread,
May 27, 2019, 3:33:35 PM5/27/19
to Terraform
I fixed the problem by going with the new syntax for 0.12 changing:
subnet_id = "${var.PUBLIC_SUBNETS[0]}"
to
subnet_id = "var.PUBLIC_SUBNETS[0]"

This also works: subnet_id = "$var.PUBLIC_SUBNETS[0]"

However in my opinion this is very counter-intuitive and very much against convention over configuration in that these following lines work fine:
  ami           = "${data.aws_ami.ubuntu.id}"
  instance_type = "${var.INSTANCE_TYPE}"

Also this passes validation and fails plan:
subnet_id = "${var.PUBLIC_SUBNETS[0]}"

Meaning there may be some inconsistency by which validate and plan works in 0.12?

Thanks for your help in looking into it and applying necessary conventions in the next release.
Thus code will be easier to read as well.

Thank you.

Mono

Monosij Dutta-Roy

unread,
May 27, 2019, 3:52:55 PM5/27/19
to Terraform
However, I may have spoken too fast.

Even after it passes plan, it fails apply in that it does not find the "$var.PUBLIC_SUBNETS[0]"

+++++++++++++++++++++++++++++++++++++++++++++++++++

Error: Error launching source instance: InvalidSubnetID.NotFound: The subnet ID '$var.PUBLIC_SUBNETS[0]' does not exist
status code: 400, request id: d856aaeb-d8c9-4bad-9f44-7d3fac8eb08f

  on ../modules/instances/instance.tf line 33, in resource "aws_instance" "instance":
  33: resource "aws_instance" "instance" {

+++++++++++++++++++++++++++++++++++++++++++++++++++

The output does state that the public subnets were created:
module.main-vpc.module.main-vpc.aws_subnet.public[1]: Creation complete after 3s [id=subnet-044e544826e970307]
module.main-vpc.module.main-vpc.aws_subnet.public[2]: Creation complete after 3s [id=subnet-048752fbd83aaa71b]
module.main-vpc.module.main-vpc.aws_subnet.public[0]: Creation complete after 3s [id=subnet-0c6616cd95cfe616c]

...
Please note I am using the module = "terraform-aws-modules/vpc/aws"

But I am using it with other examples I am working with and it works fine.

For example I am using subnets as in:
subnet_id = "${var.ENV == "prod" ? module.vpc-prod.public_subnets[0] : module.vpc-dev.public_subnets[0]}"

No problem.

But when I use this:
subnet_id = "${var.PUBLIC_SUBNETS[0]}"

Inconsistency in errors across validate/ plan/ execute, especially after passing plan and seeing that subnets are being generated.

Your help will be much appreciated in figuring this put please.

Thank you.

Mono

Stuart Clark

unread,
May 27, 2019, 5:06:58 PM5/27/19
to terrafo...@googlegroups.com, Monosij Dutta-Roy
On 27/05/2019 20:52, Monosij Dutta-Roy wrote:
However, I may have spoken too fast.

Even after it passes plan, it fails apply in that it does not find the "$var.PUBLIC_SUBNETS[0]"


As you are using 0.12 I'd recommend not using the interpolation syntax at all.

Remove the "" and $

So subnet_id = var.PUBLIC_SUBNETS[0]

And subnet_id = var.ENV == "prod" ? module.vpc-prod.public_subnets[0] : module.vpc-dev.public_subnets[0]

--
This mailing list is governed under the HashiCorp Community Guidelines - https://www.hashicorp.com/community-guidelines.html. Behavior in violation of those guidelines may result in your removal from this mailing list.
 
GitHub Issues: https://github.com/hashicorp/terraform/issues
IRC: #terraform-tool on Freenode
---
You received this message because you are subscribed to the Google Groups "Terraform" group.
To unsubscribe from this group and stop receiving emails from it, send an email to terraform-too...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/terraform-tool/365c37e4-f1f6-4bc1-9b5d-5b499cb43f0f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


-- 
Stuart Clark

Monosij Dutta-Roy

unread,
May 28, 2019, 1:36:59 PM5/28/19
to Terraform
Hi Stuart -

Thanks for your reply. However what you suggested did not work.

Thus: this: subnet_id = var.PUBLIC_SUBNETS[0] gives this error:
Error: Incorrect attribute value type
  on ../modules/instances/instance.tf line 38, in resource "aws_instance" "instance":
  38:   subnet_id = var.PUBLIC_SUBNETS[0]
Inappropriate value for attribute "subnet_id": string required.

--------------------------------------------------------
Please note my own two replies.
...
I stated in my own first reply that:

I fixed the problem by going with the new syntax for 0.12 changing:
subnet_id = "${var.PUBLIC_SUBNETS[0]}"
TO
subnet_id = "var.PUBLIC_SUBNETS[0]"

This also works: subnet_id = "$var.PUBLIC_SUBNETS[0]"

...
In my second reply I stated however that fails execute.

Thus wondering why:
"${var.PUBLIC_SUBNETS[0]}" --> passes validate, fails plan
"$var.PUBLIC_SUBNETS[0]" --> passes plan, fails apply
also
"var.PUBLIC_SUBNETS[0]"  --> passes plan, fails apply

Not only is it not working, but this this new syntax is counter-intuitive in that I mentioned:
However in my opinion this is very counter-intuitive and very much against convention over configuration in that these following lines work fine:
  ami           = "${data.aws_ami.ubuntu.id}"
  instance_type = "${var.INSTANCE_TYPE}"

BTW: this interpolation DOES work, no problem:
subnet_id = "${var.ENV == "prod" ? module.vpc-prod.public_subnets[0] : module.vpc-dev.public_subnets[0]}"

Thanks for your helping in sorting this out.

Mono
To unsubscribe from this group and stop receiving emails from it, send an email to terrafo...@googlegroups.com.


-- 
Stuart Clark

Stuart Clark

unread,
May 28, 2019, 2:18:37 PM5/28/19
to Monosij Dutta-Roy, Terraform
Where and how is var.PUBLIC_SUBNETS defined?
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.

Monosij Dutta-Roy

unread,
May 28, 2019, 3:50:59 PM5/28/19
to Terraform
Hi Stuart I have noted in my initial post that it is defined as below, but is being called in from a module - shared between environments dev and prod.

The dev.tf snippet is below, and subnets are defined in a local module vpc.tf (shared between dev and prod) which uses the terraform module: terraform-aws-modules/vpc/aws.

Hope that helps. I can send the files if necessary. Since it is part of a tutorial from Edward Viaene you can see the code here: https://github.com/wardviaene/terraform-course/tree/master/demo-18b 

It is set to work in 0.11.7 and should work in 0.11.9 but when I started with 0.12-rc1 - I had to fix some issues with tags through the different demos.


As I stated, the errors are inconsistent across validate/ plan/ apply. And it seems this "${var.SUBNETS[0])" is itself inconsistent when pulling from a array? The old declaration seemd more consistent than: var.SUBNETS[0])

Thanks again.
...
Thus in file instance.tf of dev module, PUBLIC_SUBNETS defined/ used as below. Incorporates  instance.tf and vpc.tf from the modules folder, where vpc.tf uses the terraform module: terraform-aws-modules/vpc/aws
#-------------------------------------------------#

variable "PUBLIC_SUBNETS" {
  type = "list"
}

resource "aws_instance" "instance" {
  ami           = "${data.aws_ami.ubuntu.id}"
  instance_type = "${var.INSTANCE_TYPE}"

  # the VPC subnet
  subnet_id = "${var.PUBLIC_SUBNETS[0]}" # TRIED "$var.PUBLIC_SUBNETS[0]" / "var.PUBLIC_SUBNETS[0]" / var.PUBLIC_SUBNETS[0]

  # the security group
  vpc_security_group_ids = ["${aws_security_group.allow-ssh.id}"]

  # the public SSH key
  key_name = "${aws_key_pair.mykeypair.key_name}"

  tags = {
    Name         = "instance-${var.ENV}"
    Environmnent = "${var.ENV}"
  }
}
#-------------------------------------------------#


On Tuesday, May 28, 2019 at 2:18:37 PM UTC-4, Stuart Clark wrote:
Where and how is var.PUBLIC_SUBNETS defined?

⁞ Fernando Miguel

unread,
May 28, 2019, 3:54:51 PM5/28/19
to terrafo...@googlegroups.com
Please make sure you first upgrade to 0.11.14 as that one is better prepared to migrate to 0.12

--
Fernando Miguel

To unsubscribe from this group and stop receiving emails from it, send an email to terraform-too...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/terraform-tool/1aa24e8f-ce06-4e16-8511-43fe928ed27b%40googlegroups.com.

Monosij Dutta-Roy

unread,
May 28, 2019, 5:02:21 PM5/28/19
to Terraform
Hi Fernando - I am not migrating. Brand new deployment, started with 0.12. passes 0.12 validation, plan, fails apply.

Thanks.


On Tuesday, May 28, 2019 at 3:54:51 PM UTC-4, Fernando wrote:
Please make sure you first upgrade to 0.11.14 as that one is better prepared to migrate to 0.12

--
Fernando Miguel

Stuart Clark

unread,
May 29, 2019, 5:06:42 AM5/29/19
to terrafo...@googlegroups.com, Monosij Dutta-Roy
On 28/05/2019 20:50, Monosij Dutta-Roy wrote:
Hi Stuart I have noted in my initial post that it is defined as below, but is being called in from a module - shared between environments dev and prod.

The dev.tf snippet is below, and subnets are defined in a local module vpc.tf (shared between dev and prod) which uses the terraform module: terraform-aws-modules/vpc/aws.

Hope that helps. I can send the files if necessary. Since it is part of a tutorial from Edward Viaene you can see the code here: https://github.com/wardviaene/terraform-course/tree/master/demo-18b 

It is set to work in 0.11.7 and should work in 0.11.9 but when I started with 0.12-rc1 - I had to fix some issues with tags through the different demos.


As I stated, the errors are inconsistent across validate/ plan/ apply. And it seems this "${var.SUBNETS[0])" is itself inconsistent when pulling from a array? The old declaration seemd more consistent than: var.SUBNETS[0])

Thanks again.
...
Thus in file instance.tf of dev module, PUBLIC_SUBNETS defined/ used as below. Incorporates  instance.tf and vpc.tf from the modules folder, where vpc.tf uses the terraform module: terraform-aws-modules/vpc/aws
#-------------------------------------------------#

variable "PUBLIC_SUBNETS" {
  type = "list"
}


I think you want to change this to:

type = list(string)


In general for 0.12 you don't want to be using "" very much at all - only for direct specification of strings. For numbers, booleans, variable references, etc. you just enter it directly.


To unsubscribe from this group and stop receiving emails from it, send an email to terraform-too...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/terraform-tool/1aa24e8f-ce06-4e16-8511-43fe928ed27b%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.


-- 
Stuart Clark

Monosij Dutta-Roy

unread,
Jun 2, 2019, 7:25:40 PM6/2/19
to Terraform
Hi Stuart -

That worked! Thanks! But I do have a few questions as I had to fix a few more things.

1. ---------------------------------------------------------------------->

While moving from subnet_id = "${var.PUBLIC_SUBNETS[0]}" to this subnet_id = var.PUBLIC_SUBNETS[0] along with type = list(string) worked, ...

... however, this syntax var.PUBLIC_SUBNETS[0] seems very counter-intuitve and breaks the convention over configuration?

For eg. I still have the following in my code, where I am referencing strings.
ami = "${data.aws_ami.ubuntu.id}"   and also: instance_type = "${var.INSTANCE_TYPE}"

But the above change, along with 

PUBLIC_SUBNETS = module.main-vpc.public_subnets from [PUBLIC_SUBNETS = module.main-vpc.public_subnets]
in dev.vpc worked when public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"] ( defined in modules/vpc.tf )

Here I would expect it to be an element of the array string, which goes to be a string, when cast.

2. ---------------------------------------------------------------------->

For eg. private/ publc subnets in vpc.tf defined as:
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

But I left private subnets as is, as below:

output "private_subnets" {
  description = "List of IDs of private subnets"
  value       = ["${module.main-vpc.private_subnets}"]
}

.. but had to change public subnets from ["${module.main-vpc.public_subnets}"] to:

output "public_subnets" {
  description = "List of IDs of public subnets"
  value       = module.main-vpc.public_subnets
}

To me, reading this ["${module.main-vpc.private_subnets}"] tells me I expect an array of strings, even if one string, that is cast as a string in "${var.PUBLIC_SUBNETS[0]}"

This is hard to read: subnet_id = var.PUBLIC_SUBNETS[0] and does not follow convention. Like bash or perl or any string related commands.
Also, it seems it is inconsistently applied as noted above.

3. ---------------------------------------------------------------------->

Also moving from type = list() to list type = list(string) is more explicit and is very helpful.

----------------------------------------------------------------------

In such a terse DSL like HCL, IMHO, keeping necessary conventions, keeping them consistent, also helps newer developers coming on board.

I hope you concur and perhaps you will reconsider this part of the impl in 0.12.1.

Thank you.

Mono


-- 
Stuart Clark

Stuart Clark

unread,
Jun 2, 2019, 7:32:15 PM6/2/19
to terrafo...@googlegroups.com, Monosij Dutta-Roy

The ${...} inside "" is interpolation, and in general wouldn't be used much in 0.12. Instead the direct (non-quoted) reference to variables would be the way you do things.

This has the advantage of type checking, so if a resource/module expects a list of strings it won't accept a number or a list of booleans.

However, as you note the old syntax did sometimes give you a clue that you were passing a list.


I would strongly suggest removing all "${...}" entries and just using the direct syntax. There is a tool to do this automatically - terraform 0.12upgrade

If you stick with interpolation you lose the type checking ability, which is a major advantage that 0.12 brings.


To unsubscribe from this group and stop receiving emails from it, send an email to terraform-too...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/terraform-tool/81655121-d620-4515-b916-ca01db22b86f%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.


-- 
Stuart Clark

Monosij Dutta-Roy

unread,
Jun 2, 2019, 8:37:26 PM6/2/19
to Terraform
Ok will do then and remove all interpolations. Thanks again for the direction Stuart.


-- 
Stuart Clark

Stephen Olabode

unread,
Jun 24, 2019, 3:36:48 PM6/24/19
to Terraform
Hi, 
While i went through and effected the changes, the plan worked all through till the launch of the source instance.It gave an error
" InvalidSubnetID".
How do i fix this please?

David Jeche

unread,
Jun 25, 2019, 4:30:33 AM6/25/19
to Terraform
It means that somewhere in your code the input you provided is not valid. You need to make sure you have the correct reference to subnet_id this can be by reference to a resource after creation or manually types in.

I feel like the manual implementation of subnet ID's should not be that way. Use the remote state to import them in the current run or alternatively import them manually then reference than from within terraform rather than manual input.
Reply all
Reply to author
Forward
0 new messages