hashicorp / terraform-provider-aws

The AWS Provider enables Terraform to manage AWS resources.
https://registry.terraform.io/providers/hashicorp/aws
Mozilla Public License 2.0
9.74k stars 9.1k forks source link

[Bug]: Transit Gateway Propagations keep recreating #32524

Open mmoreno43 opened 1 year ago

mmoreno43 commented 1 year ago

Terraform Core Version

1.3.7

AWS Provider Version

5.8.0

Affected Resource(s)

I have some terraform code that is supposed to add propagations to my ec2 transit gateway route table. Each time I run my terraform, the code is re-ran when no changes have been made. I believe the affected resources are:

Expected Behavior

What I expect to happen is the code to look up the ID based on the name in data sources and retrieve the ID. The ID is then used to propagate the correct attachment to my transit gateway route table.

Actual Behavior

What ends up happening is the data sources look up the name of the attachment and fetch the new ID. Terraform destroys the old propagation and creates a new one.

Now, you may be asking yourself why not use a lifecycle configuration, if I used a lifecycle rule and someone re-created a VPC attachment then the new attachment will never get associated.

Relevant Error/Panic Output Snippet

No response

Terraform Configuration Files

tgw.txt

###################### Main Module ######################

data "aws_ec2_transit_gateway_route_table" "prod" {
    provider = aws.tgw-owner
    for_each = { for name in var.prod_route_table_names : name => name }

    filter {
        name   = "tag:Name"
        values = [each.key]
    }
}

# Lookup prod attachment names
data "aws_ec2_transit_gateway_attachment" "prod" {
    provider = aws.tgw-owner
    for_each = { for name in var.prod_attachment_names : name => name }

    filter {
    name   = "state"
    values = ["available"]
  }

    filter {
        name   = "tag:Name"
        values = [each.key]
    }
}

# Lookup non Prod route table names
data "aws_ec2_transit_gateway_route_table" "non_prod" {
    provider = aws.tgw-owner
    for_each = { for name in var.non_prod_route_table_names : name => name }

    filter {
        name   = "tag:Name"
        values = [each.key]
    }
}

# Lookup non prod attachment names
data "aws_ec2_transit_gateway_attachment" "non_prod" {
    provider = aws.tgw-owner
    for_each = { for name in var.non_prod_attachment_names : name => name }

    filter {
    name   = "state"
    values = ["available"]
  }

    filter {
        name   = "tag:Name"
        values = [each.key]
    }
}

# Create route table propagation in transit gateway attachment
resource "aws_ec2_transit_gateway_route_table_propagation" "a-to-b" {
  for_each = var.prod_tgw && length(data.aws_ec2_transit_gateway_route_table.prod) > 0 ? data.aws_ec2_transit_gateway_route_table.prod : {}

  provider = aws.tgw-owner

  transit_gateway_attachment_id  = var.vpc_attachment
  transit_gateway_route_table_id = each.value.id

  lifecycle {
    ignore_changes = [
      transit_gateway_attachment_id,
      transit_gateway_route_table_id,
    ]
  }

}

# Create route table propagation in all prod vpcs
resource "aws_ec2_transit_gateway_route_table_propagation" "b-to-a" {
    for_each = var.prod_tgw && length(data.aws_ec2_transit_gateway_attachment.prod) > 0 ? data.aws_ec2_transit_gateway_attachment.prod : {}

    provider = aws.tgw-owner

    transit_gateway_attachment_id  = each.value.id
    transit_gateway_route_table_id = var.tgw_route_table

    lifecycle {
    ignore_changes = [
      transit_gateway_attachment_id,
      transit_gateway_route_table_id,
    ]
  }
}

####################### Variables #######################

variable "vpc_attachment" {
    type = string
    description = "The ID of the VPC attachment"
}

variable "tgw_route_table" {
    type = string
    description = "The ID of the route table associated to the VPC attachment"
}

variable "prod_tgw" {
    type = bool
    description = "Whether to propagate the other prod VPCs with this VPC."
    default = false
}

variable "prod_attachment_names" {
  description = "List of Transit Gateway Attachment names"
  type        = list(string)
  default     = [] # Add your names here, or set them when you call the module
}

variable "prod_route_table_names" {
  description = "List of Transit Gateway Route Table names"
  type        = list(string)
  default     = [
  ] # Add your names here, or set them when you call the module
}

variable "non_prod_tgw" {
    type = bool
    description = "Whether to propagate the other prod VPCs with this VPC."
    default = false
}

variable "non_prod_attachment_names" {
  description = "List of Transit Gateway Attachment names"
  type        = list(string)
  default     = [] # Add your names here, or set them when you call the module
}

variable "non_prod_route_table_names" {

  description = "List of Transit Gateway Route Table names"
  type        = list(string)
  default     = [
  ] # Add your names here, or set them when you call the module
}

########################## Child Module #########################

module "vpc_iaas-tgw-propagation" {

  providers = {
    aws.tgw-owner = aws.prod
    aws.vpc-owner = aws
  }

  vpc_attachment            = module.vpc_iaas-tgw-attachment.transit_gateway_attachment_id
  tgw_route_table           = module.vpc_iaas-tgw-attachment.transit_gateway_route_table_id
  prod_tgw              = true
  prod_attachment_names = ["prod-vpc-attachment", "AWS-IAAS-.0-19-attachment", ]
}

Steps to Reproduce

  1. terraform init
  2. terraform plan
  3. terraform apply
  4. Run the code again after creation and it should reproduce as though nothing is there

Debug Output

No response

Panic Output

No response

Important Factoids

No response

References

No response

Would you like to implement a fix?

None

github-actions[bot] commented 1 year ago

Community Note

Voting for Prioritization

Volunteering to Work on This Issue

justinretzolk commented 1 year ago

Hey @mmoreno43 šŸ‘‹ Thank you for taking the time to raise this! So that we have the appropriate information in order to look into this, can you supply debug logs (redacted as needed) as well?