Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resource/aws_route_table: Fix route table import to avoid deleting routes #5657

Merged
merged 2 commits into from
Feb 23, 2019

Conversation

YakDriver
Copy link
Member

@YakDriver YakDriver commented Aug 23, 2018

Fixes #5631, fixes #2270, fixes #5686

Changes proposed in this pull request:

  • [BUG FIX] Make importing route tables consistent with reading route tables so that imports match existing existing resources (which avoids deletion of existing routes on apply)
  • Update acceptance tests:
    • Test for deleting routes bug
    • Update existing acceptance tests for the improved consistency
    • Run in AWS accounts with fewer network conflicts

Output from acceptance testing:

$ make testacc TESTARGS='-run=TestAccAWSRouteTable_import'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./... -v -run=TestAccAWSRouteTable_import -timeout 120m
?   	github.com/terraform-providers/terraform-provider-aws	[no test files]
=== RUN   TestAccAWSRouteTable_importBasic
--- PASS: TestAccAWSRouteTable_importBasic (50.20s)
=== RUN   TestAccAWSRouteTable_importWithCreate
--- PASS: TestAccAWSRouteTable_importWithCreate (62.47s)
=== RUN   TestAccAWSRouteTable_importComplex
--- PASS: TestAccAWSRouteTable_importComplex (188.63s)
PASS
ok  	github.com/terraform-providers/terraform-provider-aws/aws	301.337s

@bflad bflad added bug Addresses a defect in current functionality. service/ec2 Issues and PRs that pertain to the ec2 service. breaking-change Introduces a breaking change in current functionality; usually deferred to the next major release. labels Aug 23, 2018
@bflad
Copy link
Contributor

bflad commented Aug 23, 2018

Marking as breaking change as this fundamentally changes the behavior of import for the resource.

I personally do not know the historical context of why this resource is setup to perform the complex import, but if I had to guess off top of my head, its because there is currently no method to import the separate aws_route resources.

@YakDriver
Copy link
Member Author

Add the ability to import routes. Here are the new acceptance tests directed specifically at aws_route import:

$ make testacc TESTARGS='-run=TestAccAWSRoute_import'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./... -v -run=TestAccAWSRoute_import -timeout 120m
?   	github.com/terraform-providers/terraform-provider-aws	[no test files]
=== RUN   TestAccAWSRoute_importBasic
--- PASS: TestAccAWSRoute_importBasic (51.14s)
=== RUN   TestAccAWSRoute_importIPv6IGW
--- PASS: TestAccAWSRoute_importIPv6IGW (51.20s)
=== RUN   TestAccAWSRoute_importIPv6NetworkInterface
--- PASS: TestAccAWSRoute_importIPv6NetworkInterface (177.98s)
=== RUN   TestAccAWSRoute_importWithMultipleRTs
--- PASS: TestAccAWSRoute_importWithMultipleRTs (47.10s)
PASS
ok  	github.com/terraform-providers/terraform-provider-aws/aws	327.456s

@YakDriver
Copy link
Member Author

YakDriver commented Aug 24, 2018

@bflad As you mentioned earlier, this change might be wise to consider at the same time as implementing importing aws_route resources. This PR now implements that enhancement.

This PR does fundamentally change the import of aws_route_table. However, I disagree that it is a breaking change. Here is why.

Currently, if you create an aws_route_table with an inline route, you'll end up with a state having an aws_route_table and an inline route. We'd agree that you can manage your aws_route_table from Terraform in that situation. It's not an anomalous state. I'd guess it's a situation a good chunk of, if not most, users find themselves in. I wouldn't say they are in a "breaking" condition.

If down the road, you import that exact same aws_route_table, you'll end up with a state having an aws_route_table and an aws_route. You might expect (as we did) to have the same state after the import as you did after create, but, alas, you do not. When Terraform compares your current state to the import state, it compares apples to oranges by comparing aws_route_table with inline routes (the read/current state) to aws_route_table + aws_route (the import state). The bug forces you into an anomalous state and, as a result, your routes get deleted.

This has production impact on us. When managing tenant infrastructures, when we import route tables as part of a larger import, make changes to unrelated resources, and then attempt to apply the changes, all the routes are deleted. That is the breaking issue. :)

@YakDriver YakDriver changed the title Fix route table import Add aws_route import and fix route table import Aug 24, 2018
@bflad
Copy link
Contributor

bflad commented Aug 27, 2018

@YakDriver I do really want to emphasize that this change does seem like a good path forward, its just a matter of keeping our compatibility promises. The aws_route_table import behavior has been like this for a very long time though and people may be depending on its current behavior. The maintainers are not likely to merge a change in this type of behavior before a major release, which is coming in the next few weeks to coincide with the Terraform 0.12 beta.

You have a few options for working with this today:

  • Continue with the existing code and use the following workaround: terraform state rm the newly added aws_route resources found via terraform plan if you would like to only manage via aws_route_table
  • Build and run a custom provider binary with the code changes contained in this pull request

My recommendations for this pull request in its current state to move things forward (unless we want to do all this in 2.0.0):

  • Split the two code changes here:
    • resource/aws_route: Support resource import (this can be reviewed, adjusted, and merged today)
    • resource/aws_route_table: Remove aws_route resource import (this can be reviewed, adjusted and merged in 2.0.0)
  • Create a separate PR to document the upcoming change in the Version 2 Upgrade Guide and provide [WARN] logs indicating the change of behavior. We may also want to consider properly documenting the existing behavior and available workaround(s) in the aws_route_table resource documentation, even if we are deprecating it.

@YakDriver
Copy link
Member Author

YakDriver commented Aug 27, 2018

@bflad The aws_route import PR #5687 is ready to go. I'll work on cleaning up the other two PRs and update this when they are ready to go.

@YakDriver YakDriver changed the title Add aws_route import and fix route table import Fix route table import to avoid deleting routes Aug 27, 2018
@YakDriver YakDriver force-pushed the fix-route-table-import branch 2 times, most recently from 3f3cca9 to 1ec393a Compare August 28, 2018 17:39
@YakDriver
Copy link
Member Author

YakDriver commented Aug 28, 2018

Test on master: If you run the new acceptance that checks to see if the route is deleted after import/apply on master, it fails.

$ make testacc TESTARGS='-run=TestAccAWSRouteTable_importWithCreate'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./... -v -run=TestAccAWSRouteTable_importWithCreate -timeout 120m
?   	github.com/terraform-providers/terraform-provider-aws	[no test files]
=== RUN   TestAccAWSRouteTable_importWithCreate
--- FAIL: TestAccAWSRouteTable_importWithCreate (51.20s)
	testing.go:527: Step 1 error: Failed state verification, resource with ID r-rtb-0dd113e4fe3107bdd1218385255 not found
FAIL
FAIL	github.com/terraform-providers/terraform-provider-aws/aws	51.232s
make: *** [testacc] Error 1

Test on this branch: Acceptance tests after adjusting, rebasing.

$ make testacc TESTARGS='-run=TestAccAWSRouteTable_import'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./... -v -run=TestAccAWSRouteTable_import -timeout 120m
?   	github.com/terraform-providers/terraform-provider-aws	[no test files]
=== RUN   TestAccAWSRouteTable_importBasic
--- PASS: TestAccAWSRouteTable_importBasic (53.04s)
=== RUN   TestAccAWSRouteTable_importWithCreate
--- PASS: TestAccAWSRouteTable_importWithCreate (68.20s)
=== RUN   TestAccAWSRouteTable_importComplex
--- PASS: TestAccAWSRouteTable_importComplex (186.16s)
PASS
ok  	github.com/terraform-providers/terraform-provider-aws/aws	307.443s

@YakDriver
Copy link
Member Author

@bflad Everything you suggested for implementation is ready for review, adjust, merge. Please see earlier comment for PR #s.

@YakDriver YakDriver changed the title Fix route table import to avoid deleting routes resource/aws_route_table: Fix route table import to avoid deleting routes Aug 29, 2018
@bflad bflad added this to the v2.0.0 milestone Aug 30, 2018
@YakDriver
Copy link
Member Author

This PR needs some work. Currently, with this PR:

  1. Config: route table + inline routes
    Import: route table + inline routes
    After apply: Correct (TF reports no changes needed)
  2. Config: route table + separate "correctly named" aws_route resources
    Import: route table + inline routes + separate resources
    After apply: No routes deleted but 400 errors because routes already exist (because of separate resources, and none are in the state, tries to create them)
    Expected: Import results in route table + separate resources and TF reports no changes needed and no 400 errors because of trying to create existing resources
  3. Config: route table + separate incorrectly named aws_route resources
    Import: route table + inline routes + separate resources
    After apply: No routes deleted but 400 errors because routes already exist (because of separate resources, and none are in the state, tries to create them)
    Expected: Import results in route table + separate resources and TF reports no changes needed and no 400 errors because of trying to create existing resources

Here are configs based on these scenarios that, in my opinion, should work:

  • PR makes this work now.
resource "aws_route_table" "test" {
  vpc_id = "${aws_vpc.test.id}"

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "${aws_internet_gateway.test.id}"
  }

  tags {
    Name = "bflad-testing"
  }
}
  • No deletion but you get 400 errors (recreating existing routes)
resource "aws_route_table" "test" {
  vpc_id = "${aws_vpc.test.id}"

  tags {
    Name = "bflad-testing"
  }
}

resource "aws_route" "test" {
  route_table_id         = "${aws_route_table.test.id}"
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = "${aws_internet_gateway.test.id}"
}
  • No deletion but you get 400 errors (recreating existing routes)
resource "aws_route_table" "test" {
  vpc_id = "${aws_vpc.test.id}"

  tags {
    Name = "bflad-testing"
  }
}

resource "aws_route" "randomname" {
  route_table_id         = "${aws_route_table.test.id}"
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = "${aws_internet_gateway.test.id}"
}

@bflad
Copy link
Contributor

bflad commented Aug 30, 2018

#5715 has been merged so this is ready for rebase 👍

This pull request should not worry about handling scenarios with separate aws_route resources in configurations -- its up to the operator to import the separate resource if they choose to manage their configuration in this manner. The new behavior of not including the other resources during import is more consistent with the import behavior of other resources in the provider. 😄

@bflad
Copy link
Contributor

bflad commented Aug 31, 2018

That's by design, not a problem.

The route attribute is configured as Optional and Computed:

https://github.com/terraform-providers/terraform-provider-aws/blob/ee18327b50777d6f5e3bc06277cd723c5953ef2d/aws/resource_aws_route_table.go#L44-L48

This is what allows there to be a separate aws_route resource to begin with. The lack of providing a route configuration will show no difference in the aws_route_table resource. It does not matter that the routes are saved into the Terraform state as they have no bearing unless you start configuring them in your configuration.


As an aside: the import process for a resource is an implicit call to the read function of a resource after the Importer.State function is called. The import process does not currently look at or care about the configuration, only getting information into the Terraform state.

In practice, this is why we generally only care about setting the ID or required attributes for reading in the Importer.State functions for resources -- we allow the read function to do all the work for the rest of the Terraform state and best practices for attributes are to always re-read them into the Terraform state during the read function for drift detection: https://www.terraform.io/docs/extend/best-practices/detecting-drift.html

While we currently support this "complex" import, where the import of one resource creates other resources in the Terraform state, its usage is very limited and often more confusing. At some point we may remove support for these "complex" imports or support better import models in coordination with upstream changes in Terraform core. There have been design sketches where Terraform automatically creates the configuration. The implementation of a feature like that may influence how import works in the future. We'll see. 😄

@YakDriver
Copy link
Member Author

@bflad I guess I'll stop complaining about my PR then! Thanks

@ghost ghost added the size/L Managed by automation to categorize the size of a PR. label Sep 11, 2018
@ghost ghost added size/L Managed by automation to categorize the size of a PR. tests PRs: expanded test coverage. Issues: expanded coverage, enhancements to test infrastructure. labels Sep 18, 2018
@ghost ghost added size/L Managed by automation to categorize the size of a PR. tests PRs: expanded test coverage. Issues: expanded coverage, enhancements to test infrastructure. labels Sep 19, 2018
@ghost ghost added size/L Managed by automation to categorize the size of a PR. tests PRs: expanded test coverage. Issues: expanded coverage, enhancements to test infrastructure. labels Sep 20, 2018
@YakDriver YakDriver force-pushed the fix-route-table-import branch 2 times, most recently from ea0f3f4 to 7ee437f Compare September 27, 2018 00:41
@ghost ghost added size/L Managed by automation to categorize the size of a PR. tests PRs: expanded test coverage. Issues: expanded coverage, enhancements to test infrastructure. labels Sep 27, 2018
Import route tables using inline routes in the resource data. This
is the same way resource data is structured when routes tables are
read (and created) which enables imports to line up properly with
existing resources.

Previously, if you applied a state that included the import of a
route table, all routes in the route table would be deleted. This
bug occurred because the import function
(resourceAwsRouteTableImportState()) would return a target state
including both a route table resource and separate route resources
for each route. The route table read function
(resourceAwsRouteTableRead()) returns a state with a route table
resource having inline routes. Despite being equivalent, since the
states did not match, Terraform would delete all routes in the
route table when applying the change plan.

Fixes hashicorp#5631

Update functions names to comply with convention

This commit is planned to occur after PR hashicorp#5687 which changes the
names of these functions. In order to avoid merge conflicts at that
time, this pre-emptively renames the functions.
Use checks that align with inline routes in the state. Improve
tests to avoid network values that will conflict with fewer AWS
accounts.

Previously, route table import acceptance tests only checked the
length of the state (1 for route table, and 1 for each separate
route resource). This simple test did not check much, especially
when checking route tables with inline routes.

Now, the state is checked to make sure it has routes and a route-
count attribute that matches to expected value.
Copy link
Contributor

@bflad bflad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for your dedication and patience here, @YakDriver! We're currently in the process of pulling version 2.0.0 related changes and this one is ready to go. 🚀

Output from acceptance testing:

--- PASS: TestAccAWSRouteTable_panicEmptyRoute (15.79s)
--- PASS: TestAccAWSRouteTable_ipv6 (25.46s)
--- PASS: TestAccAWSRouteTable_vpcPeering (36.18s)
--- PASS: TestAccAWSRouteTable_tags (36.75s)
--- PASS: TestAccAWSRouteTable_vgwRoutePropagation (37.36s)
--- PASS: TestAccAWSRouteTable_importBasic (37.53s)
--- PASS: TestAccAWSRouteTable_importWithCreate (48.96s)
--- PASS: TestAccAWSRouteTable_basic (50.77s)
--- PASS: TestAccAWSRouteTable_instance (150.77s)
--- PASS: TestAccAWSRouteTable_Route_TransitGatewayID (290.56s)

@bflad bflad merged commit 68f28fa into hashicorp:master Feb 23, 2019
bflad added a commit that referenced this pull request Feb 23, 2019
@YakDriver YakDriver deleted the fix-route-table-import branch February 25, 2019 18:31
@ghost
Copy link

ghost commented Mar 31, 2020

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!

@ghost ghost locked and limited conversation to collaborators Mar 31, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
breaking-change Introduces a breaking change in current functionality; usually deferred to the next major release. bug Addresses a defect in current functionality. service/ec2 Issues and PRs that pertain to the ec2 service. size/L Managed by automation to categorize the size of a PR. tests PRs: expanded test coverage. Issues: expanded coverage, enhancements to test infrastructure.
Projects
None yet
3 participants