Terraform v0.11.3
Please list the resources as a list, for example:
module "NLB-public" {
source = "../../modules/ec2/nlb/public/"
nlb_name = "${local.environment}-public"
nlb_enable_deletion_protection = true
nlb_enable_cross_zone_load_balancing = true
nlb_subnet_mappings = [
{
subnet_id = "${element(module.VPC.public_subnets, 0)}"
allocation_id = "${module.EIP-public-nlb.eip_id}"
},
]
resource "aws_lb" "nlb" {
name = "${var.nlb_name}"
internal = false
load_balancer_type = "network"
enable_deletion_protection = "${var.nlb_enable_deletion_protection}"
enable_cross_zone_load_balancing = "${var.nlb_enable_cross_zone_load_balancing}"
tags = "${var.nlb_tags}"
subnet_mapping = ["${var.nlb_subnet_mappings}"]
}
Terraform should be able to create the aws_lb with subnet_mapping using the output of other resources like aws_subnet and aws_eip.
When using computed values like the output of aws_eip and aws_subnet, the module fails. But if I pass static strings in the same way, it works.
Error: module.NLB-public.aws_lb.nlb: "subnet_mapping.0.subnet_id": required field is not set
terraform applyNone
this is also something I am hitting and would love to see fixed/improved.
very much +1 as well.
Mine allows me to pass in values from data:
resource aws_lb default {
name = "${var.defaultname}"
internal = false
load_balancer_type = "application"
security_groups = ["${data.aws_security_group.lb.id}"]
enable_deletion_protection = "${var.enable_deletion_protection_lb}"
subnet_mapping {
subnet_id = "${data.aws_subnet.publ_a.id}"
}
subnet_mapping {
subnet_id = "${data.aws_subnet.publ_b.id}"
}
}
BUT...
every plan that I run it wants to delete and recreate my lb because it says the subnet mapping is changing when it is not.
-/+ module.accounts.module.staging.module.us-west-2.module.sso.aws_lb.default (new resource required)
id: "arn:aws:elasticloadbalancing:us-west-2:redacted:loadbalancer/redacted/redacted/redacted" => <computed> (forces new resource)
access_logs.#: "0" => <computed>
arn: "arn:aws:elasticloadbalancing:us-west-2:redacted:loadbalancer/redacted/redacted/redacted" => <computed>
arn_suffix: "redacted/redacted/redacted" => <computed>
dns_name: "redacted-redacted.us-west-2.elb.amazonaws.com" => <computed>
enable_deletion_protection: "false" => "false"
enable_http2: "true" => "true"
idle_timeout: "60" => "60"
internal: "false" => "false"
ip_address_type: "ipv4" => <computed>
load_balancer_type: "application" => "application"
name: "redacted" => "redacted"
security_groups.#: "1" => "1"
security_groups.3485198027: "sg-redactedc" => "sg-redactedc"
subnet_mapping.#: "0" => "2" (forces new resource)
subnet_mapping.2175746748.allocation_id: "" => ""
subnet_mapping.2175746748.subnet_id: "" => "subnet-redacteda" (forces new resource)
subnet_mapping.3360964316.allocation_id: "" => ""
subnet_mapping.3360964316.subnet_id: "" => "subnet-redactedb" (forces new resource)
subnets.#: "2" => <computed>
tags.%: "1" => "1"
tags.Name: "redacted" => "corp-sso"
vpc_id: "vpc-redacted" => <computed>
zone_id: "redacted" => <computed>
Mine might be a separate issue. I hard-coded the values in and it still keeps recreating the LB saying I'm going from 0 subnet mappings to 2. Do you think I should make a new issue on this or is this maybe related?
adding the following has been my workaround for now.
lifecycle {
ignore_changes = ["subnet_mapping"]
}
very much +1 as well.
@GeoffMillerAZ, Can you show what you did to get around this in the meantime?
@armon @mitchellh are there any plans to have this fixed in the future releases?
+1 on this getting this fixed.
Hi folks 👋 This issue is resolved in Terraform 0.12, which supports new functionality in the configuration language aimed at solving problems like these. The new dynamic block syntax can be used to dynamically generate configuration blocks and their arguments. These can be combined with the new null value, which can be used to omit arguments as if they were not defined in the configuration at all.
For example, given this configuration:
# main.tf
terraform {
required_providers {
aws = "2.20.0"
}
required_version = "0.12.5"
}
provider "aws" {
region = "us-east-1"
}
data "aws_availability_zones" "available" {
state = "available"
}
resource "aws_vpc" "test" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "test" {
count = 2
availability_zone = "${element(data.aws_availability_zones.available.names, count.index)}"
cidr_block = "10.0.${count.index}.0/24"
vpc_id = aws_vpc.test.id
}
module "test1" {
source = "./module1"
subnet_mappings = [for subnet in aws_subnet.test :
{
allocation_id = null
subnet_id = subnet.id
}
]
}
module "test2" {
source = "./module1"
subnet_mappings = [
{
allocation_id = null
subnet_id = aws_subnet.test[0].id
},
{
allocation_id = null
subnet_id = aws_subnet.test[1].id
},
]
}
# module1/main.tf
variable "subnet_mappings" {
type = list(object({
allocation_id = string
subnet_id = string
}))
}
resource "aws_lb" "test" {
internal = true
name = "test"
dynamic "subnet_mapping" {
# The for_each argument is a hardcoded list in this illustrative example,
# however it can be sourced from a variable or local value as well as
# support multiple argument values as a map.
for_each = var.subnet_mappings
content {
allocation_id = subnet_mapping.value.allocation_id
subnet_id = subnet_mapping.value.subnet_id
}
}
}
Produces the following apply output:
$ terraform apply
data.aws_availability_zones.available: Refreshing state...
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_subnet.test[0] will be created
+ resource "aws_subnet" "test" {
+ arn = (known after apply)
+ assign_ipv6_address_on_creation = false
+ availability_zone = "us-east-1a"
+ availability_zone_id = (known after apply)
+ cidr_block = "10.0.0.0/24"
+ id = (known after apply)
+ ipv6_cidr_block = (known after apply)
+ ipv6_cidr_block_association_id = (known after apply)
+ map_public_ip_on_launch = false
+ owner_id = (known after apply)
+ vpc_id = (known after apply)
}
# aws_subnet.test[1] will be created
+ resource "aws_subnet" "test" {
+ arn = (known after apply)
+ assign_ipv6_address_on_creation = false
+ availability_zone = "us-east-1b"
+ availability_zone_id = (known after apply)
+ cidr_block = "10.0.1.0/24"
+ id = (known after apply)
+ ipv6_cidr_block = (known after apply)
+ ipv6_cidr_block_association_id = (known after apply)
+ map_public_ip_on_launch = false
+ owner_id = (known after apply)
+ vpc_id = (known after apply)
}
# aws_vpc.test will be created
+ resource "aws_vpc" "test" {
+ arn = (known after apply)
+ assign_generated_ipv6_cidr_block = false
+ cidr_block = "10.0.0.0/16"
+ default_network_acl_id = (known after apply)
+ default_route_table_id = (known after apply)
+ default_security_group_id = (known after apply)
+ dhcp_options_id = (known after apply)
+ enable_classiclink = (known after apply)
+ enable_classiclink_dns_support = (known after apply)
+ enable_dns_hostnames = (known after apply)
+ enable_dns_support = true
+ id = (known after apply)
+ instance_tenancy = "default"
+ ipv6_association_id = (known after apply)
+ ipv6_cidr_block = (known after apply)
+ main_route_table_id = (known after apply)
+ owner_id = (known after apply)
}
# module.test1.aws_lb.test will be created
+ resource "aws_lb" "test" {
+ arn = (known after apply)
+ arn_suffix = (known after apply)
+ dns_name = (known after apply)
+ enable_deletion_protection = false
+ enable_http2 = true
+ id = (known after apply)
+ idle_timeout = 60
+ internal = true
+ ip_address_type = (known after apply)
+ load_balancer_type = "application"
+ name = "test"
+ security_groups = (known after apply)
+ subnets = (known after apply)
+ vpc_id = (known after apply)
+ zone_id = (known after apply)
+ subnet_mapping {
+ subnet_id = (known after apply)
}
+ subnet_mapping {
+ subnet_id = (known after apply)
}
}
# module.test2.aws_lb.test will be created
+ resource "aws_lb" "test" {
+ arn = (known after apply)
+ arn_suffix = (known after apply)
+ dns_name = (known after apply)
+ enable_deletion_protection = false
+ enable_http2 = true
+ id = (known after apply)
+ idle_timeout = 60
+ internal = true
+ ip_address_type = (known after apply)
+ load_balancer_type = "application"
+ name = "test"
+ security_groups = (known after apply)
+ subnets = (known after apply)
+ vpc_id = (known after apply)
+ zone_id = (known after apply)
+ subnet_mapping {
+ subnet_id = (known after apply)
}
+ subnet_mapping {
+ subnet_id = (known after apply)
}
}
Plan: 5 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_vpc.test: Creating...
aws_vpc.test: Creation complete after 1s [id=vpc-0d36d77bb34cecd44]
aws_subnet.test[1]: Creating...
aws_subnet.test[0]: Creating...
aws_subnet.test[0]: Creation complete after 1s [id=subnet-08e6644b5a81f85ad]
aws_subnet.test[1]: Creation complete after 1s [id=subnet-083865752394ecc45]
module.test2.aws_lb.test: Creating...
module.test1.aws_lb.test: Creating...
module.test2.aws_lb.test: Still creating... [10s elapsed]
module.test1.aws_lb.test: Still creating... [10s elapsed]
module.test1.aws_lb.test: Still creating... [20s elapsed]
module.test2.aws_lb.test: Still creating... [20s elapsed]
module.test1.aws_lb.test: Still creating... [30s elapsed]
module.test2.aws_lb.test: Still creating... [30s elapsed]
module.test2.aws_lb.test: Still creating... [40s elapsed]
module.test1.aws_lb.test: Still creating... [40s elapsed]
module.test1.aws_lb.test: Still creating... [50s elapsed]
module.test2.aws_lb.test: Still creating... [50s elapsed]
module.test1.aws_lb.test: Still creating... [1m0s elapsed]
module.test2.aws_lb.test: Still creating... [1m0s elapsed]
module.test1.aws_lb.test: Still creating... [1m10s elapsed]
module.test2.aws_lb.test: Still creating... [1m10s elapsed]
module.test1.aws_lb.test: Still creating... [1m20s elapsed]
module.test2.aws_lb.test: Still creating... [1m20s elapsed]
module.test1.aws_lb.test: Still creating... [1m30s elapsed]
module.test2.aws_lb.test: Still creating... [1m30s elapsed]
module.test1.aws_lb.test: Still creating... [1m40s elapsed]
module.test2.aws_lb.test: Still creating... [1m40s elapsed]
module.test2.aws_lb.test: Still creating... [1m50s elapsed]
module.test1.aws_lb.test: Still creating... [1m50s elapsed]
module.test2.aws_lb.test: Still creating... [2m0s elapsed]
module.test1.aws_lb.test: Still creating... [2m0s elapsed]
module.test1.aws_lb.test: Still creating... [2m10s elapsed]
module.test2.aws_lb.test: Still creating... [2m10s elapsed]
module.test1.aws_lb.test: Still creating... [2m20s elapsed]
module.test2.aws_lb.test: Still creating... [2m20s elapsed]
module.test2.aws_lb.test: Creation complete after 2m23s [id=arn:aws:elasticloadbalancing:us-east-1:067819342479:loadbalancer/app/test/e96b1fef116b21ac]
module.test1.aws_lb.test: Creation complete after 2m23s [id=arn:aws:elasticloadbalancing:us-east-1:067819342479:loadbalancer/app/test/e96b1fef116b21ac]
Apply complete! Resources: 5 added, 0 changed, 0 destroyed.
Enjoy! 🚀
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 feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. Thanks!
Most helpful comment
Mine allows me to pass in values from data:
BUT...
every plan that I run it wants to delete and recreate my lb because it says the subnet mapping is changing when it is not.
edit:
Mine might be a separate issue. I hard-coded the values in and it still keeps recreating the LB saying I'm going from 0 subnet mappings to 2. Do you think I should make a new issue on this or is this maybe related?
adding the following has been my workaround for now.