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.75k stars 9.11k forks source link

Terraform detects changes in route_table routes because it detects that null != “” #17198

Open rajaie-sg opened 3 years ago

rajaie-sg commented 3 years ago

Community Note

Terraform CLI and Terraform AWS Provider Version

Terraform v0.14.4
+ provider registry.terraform.io/hashicorp/aws v3.24.1

Affected Resource(s)

Terraform Configuration Files

Please include all Terraform configurations required to reproduce the bug. Bug reports without a functional reproduction may be closed without investigation.

resource "aws_route_table" "main" {
  tags = {
    Name = "xxxxxxx"
  }
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "igw-xxxxxx"
  }
  route {
    cidr_block                = "xxxxxx"
    vpc_peering_connection_id = "pcx-xxxxxxxx" 
  }
}

Debug Output

Panic Output

Expected Behavior

I have a route table resource with routes defined. When I updated a route, terraform plan should show that only that specific route has changed.

Actual Behavior

What happens is that terraform plan shows that the route I changed + all other routes defined in the table have changed since it sees that the value for some attributes is now null and not an empty string "".

route            = [
          - {
              - cidr_block                = "0.0.0.0/0"
              - egress_only_gateway_id    = ""
              - gateway_id                = "igw-xxxx"
              - instance_id               = ""
              - ipv6_cidr_block           = ""
              - nat_gateway_id            = ""
              - network_interface_id      = ""
              - transit_gateway_id        = ""
              - vpc_peering_connection_id = ""
            },
          + {
              + cidr_block                = "0.0.0.0/0"
              + egress_only_gateway_id    = null
              + gateway_id                = "igw-xxxx"
              + instance_id               = null
              + ipv6_cidr_block           = null
              + nat_gateway_id            = null
              + network_interface_id      = null
              + transit_gateway_id        = null
              + vpc_peering_connection_id = null
            },

I found several posts referencing the same issue:

I am only using the aws_route_table resource, not the aws_route resource.

Steps to Reproduce

  1. Create an aws_route_table resource with multiple routes defined
  2. terraform apply --auto-approve
  3. Update a single route in the route table
  4. terraform plan
  5. You will see the other routes being modified.

Important Factoids

References

ewbankkit commented 3 years ago

@rajaie-sg Thanks for raising this issue. As I noticed in this comment, the diff between null and "" can be addressed once #14197 is resolved.

whyman commented 3 years ago

Still happening with 3.46.0

amorozkin commented 2 years ago

Same issue.

`terraform version Terraform v1.0.8 on darwin_amd64

t0rr3sp3dr0 commented 2 years ago

It is still a problem on Terraform v1.0.10 with AWS Provider v3.64.0

kderck commented 2 years ago

It is still a problem on Terraform v1.1.4 with AWS Provider v3.72.0

bryantbiggs commented 2 years ago

Terraform: v1.1.7 AWS Provider: v4.4.0

I'm seeing this diff on every plan/apply. I have tried:

My next bet is to try to use aws_route instead but this is within a module and using the nested routes in the table definition made this easier.

resource "aws_route_table" "this" {
        id               = "rtb-0cff49705ada63209"
      ~ route            = [
          + {
              + carrier_gateway_id         = ""
              + cidr_block                 = ""
              + destination_prefix_list_id = ""
              + egress_only_gateway_id     = ""
              + gateway_id                 = "eigw-053f11ad6e60b5260"
              + instance_id                = ""
              + ipv6_cidr_block            = "::/0"
              + local_gateway_id           = ""
              + nat_gateway_id             = ""
              + network_interface_id       = ""
              + transit_gateway_id         = ""
              + vpc_endpoint_id            = ""
              + vpc_peering_connection_id  = ""
            },
          - {
              - carrier_gateway_id         = ""
              - cidr_block                 = ""
              - destination_prefix_list_id = ""
              - egress_only_gateway_id     = "eigw-053f11ad6e60b5260"
              - gateway_id                 = ""
              - instance_id                = ""
              - ipv6_cidr_block            = "::/0"
              - local_gateway_id           = ""
              - nat_gateway_id             = ""
              - network_interface_id       = ""
              - transit_gateway_id         = ""
              - vpc_endpoint_id            = ""
              - vpc_peering_connection_id  = ""
            },
        ]
        tags             = {
            "Example"    = "vpc-ex-simple"
            "GithubRepo" = "terraform-aws-vpc-v4"
            "Name"       = "vpc-ex-simple-private-shared"
        }
 }
cklingspor commented 2 years ago

My next bet is to try to use aws_route instead but this is within a module and using the nested routes in the table definition made this easier.

Using the aws_route resource worked for me.

Terraform: v1.1.9 AWS Provider: v4.13.0

shichengripple001 commented 2 years ago

is this going to be fixed?

Emru1 commented 1 year ago

any changes on this?

imsathyakumar commented 9 months ago

@ewbankkit Still having the same issue for the inline routes in the Route table though aws provider is upgraded to the latest.

terraform version
Terraform v1.3.8
on darwin_arm64
+ provider registry.terraform.io/hashicorp/aws v5.29.0

Here is the code:

resource "aws_route_table" "rts" {
  for_each = {
    for rt in var.rt_config : "${data.aws_region.current.name}-${rt.name}" => rt
    if rt.create
  }
  vpc_id = each.value.vpc_id
  tags   = { "Name" = each.value.name }
  dynamic "route" {
    for_each = each.value.routes != null ? toset([for r in each.value.routes : r.destination_cidr_block]) : []
    content {
      cidr_block         = route.value
      transit_gateway_id = lookup({ for r in each.value.routes : r.destination_cidr_block => r.gateway_type == "transit" ? r.gateway_id : null }, route.value, null)
      nat_gateway_id     = lookup({ for r in each.value.routes : r.destination_cidr_block => r.gateway_type == "nat" ? r.gateway_id : null }, route.value, null)
      gateway_id         = lookup({ for r in each.value.routes : r.destination_cidr_block => r.gateway_type == "internet" ? r.gateway_id : null }, route.value, null)
      vpc_endpoint_id    = lookup({ for r in each.value.routes : r.destination_cidr_block => r.gateway_type == "firewall" ? r.gateway_id : null }, route.value, null)
    }
  }
}

variable "rt_config" {
  type = list(object({
    create      = optional(bool, true)
    name        = string
    vpc_id      = string
    attach_type = optional(string, null)
    attach_id   = optional(string, null)
    routes = optional(list(object({
      destination_cidr_block = string
      gateway_type           = string
      gateway_id             = string
    })), [])
  }))
  default     = []
  description = "configuration of the route tables, route table associations, and routes"
}

Here is the plan out:

 ~ resource "aws_route_table" "rts" {
        id               = "rtb-XXXXXXXXXX"
      ~ route            = [
          - {
              - carrier_gateway_id         = ""
              - cidr_block                 = "0.0.0.0/0"
              - core_network_arn           = ""
              - destination_prefix_list_id = ""
              - egress_only_gateway_id     = ""
              - gateway_id                 = ""
              - ipv6_cidr_block            = ""
              - local_gateway_id           = ""
              - nat_gateway_id             = ""
              - network_interface_id       = ""
              - transit_gateway_id         = "igw-XXXXXXXX"
              - vpc_endpoint_id            = ""
              - vpc_peering_connection_id  = ""
            },
          + {
              + carrier_gateway_id         = ""
              + cidr_block                 = "10.0.0.0/8"
              + core_network_arn           = ""
              + destination_prefix_list_id = ""
              + egress_only_gateway_id     = ""
              + gateway_id                 = ""
              + ipv6_cidr_block            = ""
              + local_gateway_id           = ""
              + nat_gateway_id             = ""
              + network_interface_id       = ""
              + transit_gateway_id         = "tgw-XXXXXXXX"
              + vpc_endpoint_id            = ""
              + vpc_peering_connection_id  = ""
            },
          + {
              + carrier_gateway_id         = null
              + cidr_block                 = "0.0.0.0/0"
              + core_network_arn           = null
              + destination_prefix_list_id = null
              + egress_only_gateway_id     = null
              + gateway_id                 = null
              + ipv6_cidr_block            = null
              + local_gateway_id           = null
              + nat_gateway_id             = null
              + network_interface_id       = null
              + transit_gateway_id         = "igw-XXXXXXXX"
              + vpc_endpoint_id            = null
              + vpc_peering_connection_id  = null
            },
        ]
        tags             = {
            "Name" = "my-rt"
        }
        # (5 unchanged attributes hidden)
    }

Before running the above plan, 0.0.0.0/0 route existed. Received the above plan output when 10.0.0.0/8 route is added. You can see the 0.0.0.0/0 is also getting modified when 10.0.0.0/8 is added, but when no new input provided, recevied No changes to the infrastructure.

ph-l commented 1 month ago

@ewbankkit Where would the diff between null and "" be resolved? Is it specific to aws_route_table only?