From 3f472eb2b932fb81b4ad16a2d87c88560a87917a Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 22 Aug 2018 17:39:33 -0400 Subject: [PATCH] Fix route table importing to avoid route deletion 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 #5631 Update functions names to comply with convention This commit is planned to occur after PR #5687 which changes the names of these functions. In order to avoid merge conflicts at that time, this pre-emptively renames the functions. --- aws/import_aws_route_table.go | 107 -------------------------------- aws/resource_aws_route_table.go | 13 +++- 2 files changed, 12 insertions(+), 108 deletions(-) delete mode 100644 aws/import_aws_route_table.go diff --git a/aws/import_aws_route_table.go b/aws/import_aws_route_table.go deleted file mode 100644 index 6934245a299..00000000000 --- a/aws/import_aws_route_table.go +++ /dev/null @@ -1,107 +0,0 @@ -package aws - -import ( - "fmt" - "log" - - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/hashicorp/terraform/helper/schema" -) - -// Route table import also imports all the rules -func resourceAwsRouteTableImportState( - d *schema.ResourceData, - meta interface{}) ([]*schema.ResourceData, error) { - conn := meta.(*AWSClient).ec2conn - - // First query the resource itself - id := d.Id() - resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesInput{ - RouteTableIds: []*string{&id}, - }) - if err != nil { - return nil, err - } - if len(resp.RouteTables) < 1 || resp.RouteTables[0] == nil { - return nil, fmt.Errorf("route table %s is not found", id) - } - table := resp.RouteTables[0] - - // Start building our results - results := make([]*schema.ResourceData, 1, - 2+len(table.Associations)+len(table.Routes)) - results[0] = d - log.Print("[WARN] RouteTable imports will be handled differently in a future version.") - log.Printf("[WARN] This import will create %d resources (aws_route_table, aws_route, aws_route_table_association).", len(results)) - log.Print("[WARN] In the future, only 1 aws_route_table resource will be created with inline routes.") - - { - // Construct the routes - subResource := resourceAwsRoute() - for _, route := range table.Routes { - // Ignore the local/default route - if route.GatewayId != nil && *route.GatewayId == "local" { - continue - } - - if route.Origin != nil && *route.Origin == "EnableVgwRoutePropagation" { - continue - } - - if route.DestinationPrefixListId != nil { - // Skipping because VPC endpoint routes are handled separately - // See aws_vpc_endpoint - continue - } - - // Minimal data for route - d := subResource.Data(nil) - d.SetType("aws_route") - d.Set("route_table_id", id) - d.Set("destination_cidr_block", route.DestinationCidrBlock) - d.Set("destination_ipv6_cidr_block", route.DestinationIpv6CidrBlock) - d.SetId(resourceAwsRouteID(d, route)) - results = append(results, d) - } - } - - { - // Construct the associations - subResource := resourceAwsRouteTableAssociation() - for _, assoc := range table.Associations { - if *assoc.Main { - // Ignore - continue - } - - // Minimal data for route - d := subResource.Data(nil) - d.SetType("aws_route_table_association") - d.Set("route_table_id", assoc.RouteTableId) - d.SetId(*assoc.RouteTableAssociationId) - results = append(results, d) - } - } - - { - // Construct the main associations. We could do this above but - // I keep this as a separate section since it is a separate resource. - subResource := resourceAwsMainRouteTableAssociation() - for _, assoc := range table.Associations { - if !*assoc.Main { - // Ignore - continue - } - - // Minimal data for route - d := subResource.Data(nil) - d.SetType("aws_main_route_table_association") - d.Set("route_table_id", id) - d.Set("vpc_id", table.VpcId) - d.SetId(*assoc.RouteTableAssociationId) - results = append(results, d) - } - } - - return results, nil -} diff --git a/aws/resource_aws_route_table.go b/aws/resource_aws_route_table.go index a2010ce09f9..fb4b5b7e90f 100644 --- a/aws/resource_aws_route_table.go +++ b/aws/resource_aws_route_table.go @@ -21,7 +21,18 @@ func resourceAwsRouteTable() *schema.Resource { Update: resourceAwsRouteTableUpdate, Delete: resourceAwsRouteTableDelete, Importer: &schema.ResourceImporter{ - State: resourceAwsRouteTableImportState, + State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + log.Printf("[INFO] Importing Route Table ID: %s", d.Id()) + + err := resourceAwsRouteTableRead(d, meta) + if err != nil { + return nil, err + } + + results := make([]*schema.ResourceData, 1) + results[0] = d + return results, nil + }, }, Schema: map[string]*schema.Schema{