Skip to content

Commit 49ecfe8

Browse files
authored
provider/aws: Add aws_default_route_table resource (hashicorp#8323)
* provider/aws: Add docs for Default Route Table * add new default_route_table_id attribute, test to VPC * stub * add warning to docs * rough implementation * first test * update test, add swap test * fix typo
1 parent ab5b463 commit 49ecfe8

8 files changed

Lines changed: 583 additions & 2 deletions

File tree

builtin/providers/aws/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ func Provider() terraform.ResourceProvider {
268268
"aws_nat_gateway": resourceAwsNatGateway(),
269269
"aws_network_acl": resourceAwsNetworkAcl(),
270270
"aws_default_network_acl": resourceAwsDefaultNetworkAcl(),
271+
"aws_default_route_table": resourceAwsDefaultRouteTable(),
271272
"aws_network_acl_rule": resourceAwsNetworkAclRule(),
272273
"aws_network_interface": resourceAwsNetworkInterface(),
273274
"aws_opsworks_application": resourceAwsOpsworksApplication(),
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
package aws
2+
3+
import (
4+
"fmt"
5+
"log"
6+
7+
"github.com/aws/aws-sdk-go/aws"
8+
"github.com/aws/aws-sdk-go/service/ec2"
9+
"github.com/hashicorp/terraform/helper/schema"
10+
)
11+
12+
func resourceAwsDefaultRouteTable() *schema.Resource {
13+
return &schema.Resource{
14+
Create: resourceAwsDefaultRouteTableCreate,
15+
Read: resourceAwsDefaultRouteTableRead,
16+
Update: resourceAwsRouteTableUpdate,
17+
Delete: resourceAwsDefaultRouteTableDelete,
18+
19+
Schema: map[string]*schema.Schema{
20+
"default_route_table_id": &schema.Schema{
21+
Type: schema.TypeString,
22+
Required: true,
23+
ForceNew: true,
24+
},
25+
26+
"vpc_id": &schema.Schema{
27+
Type: schema.TypeString,
28+
Computed: true,
29+
},
30+
31+
"propagating_vgws": &schema.Schema{
32+
Type: schema.TypeSet,
33+
Optional: true,
34+
Elem: &schema.Schema{Type: schema.TypeString},
35+
Set: schema.HashString,
36+
},
37+
38+
"route": &schema.Schema{
39+
Type: schema.TypeSet,
40+
Computed: true,
41+
Optional: true,
42+
Elem: &schema.Resource{
43+
Schema: map[string]*schema.Schema{
44+
"cidr_block": &schema.Schema{
45+
Type: schema.TypeString,
46+
Required: true,
47+
},
48+
49+
"gateway_id": &schema.Schema{
50+
Type: schema.TypeString,
51+
Optional: true,
52+
},
53+
54+
"instance_id": &schema.Schema{
55+
Type: schema.TypeString,
56+
Optional: true,
57+
},
58+
59+
"nat_gateway_id": &schema.Schema{
60+
Type: schema.TypeString,
61+
Optional: true,
62+
},
63+
64+
"vpc_peering_connection_id": &schema.Schema{
65+
Type: schema.TypeString,
66+
Optional: true,
67+
},
68+
69+
"network_interface_id": &schema.Schema{
70+
Type: schema.TypeString,
71+
Optional: true,
72+
},
73+
},
74+
},
75+
Set: resourceAwsRouteTableHash,
76+
},
77+
78+
"tags": tagsSchema(),
79+
},
80+
}
81+
}
82+
83+
func resourceAwsDefaultRouteTableCreate(d *schema.ResourceData, meta interface{}) error {
84+
d.SetId(d.Get("default_route_table_id").(string))
85+
86+
conn := meta.(*AWSClient).ec2conn
87+
rtRaw, _, err := resourceAwsRouteTableStateRefreshFunc(conn, d.Id())()
88+
if err != nil {
89+
return err
90+
}
91+
if rtRaw == nil {
92+
log.Printf("[WARN] Default Route Table not found")
93+
d.SetId("")
94+
return nil
95+
}
96+
97+
rt := rtRaw.(*ec2.RouteTable)
98+
99+
d.Set("vpc_id", rt.VpcId)
100+
101+
// revoke all default and pre-existing routes on the default route table.
102+
// In the UPDATE method, we'll apply only the rules in the configuration.
103+
log.Printf("[DEBUG] Revoking default routes for Default Route Table for %s", d.Id())
104+
if err := revokeAllRouteTableRules(d.Id(), meta); err != nil {
105+
return err
106+
}
107+
108+
return resourceAwsRouteTableUpdate(d, meta)
109+
}
110+
111+
func resourceAwsDefaultRouteTableRead(d *schema.ResourceData, meta interface{}) error {
112+
conn := meta.(*AWSClient).ec2conn
113+
// look up default route table for VPC
114+
filter1 := &ec2.Filter{
115+
Name: aws.String("association.main"),
116+
Values: []*string{aws.String("true")},
117+
}
118+
filter2 := &ec2.Filter{
119+
Name: aws.String("vpc-id"),
120+
Values: []*string{aws.String(d.Get("vpc_id").(string))},
121+
}
122+
123+
findOpts := &ec2.DescribeRouteTablesInput{
124+
Filters: []*ec2.Filter{filter1, filter2},
125+
}
126+
127+
resp, err := conn.DescribeRouteTables(findOpts)
128+
if err != nil {
129+
return err
130+
}
131+
132+
if len(resp.RouteTables) < 1 || resp.RouteTables[0] == nil {
133+
return fmt.Errorf("Default Route table not found")
134+
}
135+
136+
rt := resp.RouteTables[0]
137+
138+
d.Set("default_route_table_id", rt.RouteTableId)
139+
d.SetId(*rt.RouteTableId)
140+
141+
// re-use regular AWS Route Table READ. This is an extra API call but saves us
142+
// from trying to manually keep parity
143+
return resourceAwsRouteTableRead(d, meta)
144+
}
145+
146+
func resourceAwsDefaultRouteTableDelete(d *schema.ResourceData, meta interface{}) error {
147+
log.Printf("[WARN] Cannot destroy Default Route Table. Terraform will remove this resource from the state file, however resources may remain.")
148+
d.SetId("")
149+
return nil
150+
}
151+
152+
// revokeAllRouteTableRules revoke all routes on the Default Route Table
153+
// This should only be ran once at creation time of this resource
154+
func revokeAllRouteTableRules(defaultRouteTableId string, meta interface{}) error {
155+
conn := meta.(*AWSClient).ec2conn
156+
log.Printf("\n***\nrevokeAllRouteTableRules\n***\n")
157+
158+
resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesInput{
159+
RouteTableIds: []*string{aws.String(defaultRouteTableId)},
160+
})
161+
if err != nil {
162+
return err
163+
}
164+
165+
if len(resp.RouteTables) < 1 || resp.RouteTables[0] == nil {
166+
return fmt.Errorf("Default Route table not found")
167+
}
168+
169+
rt := resp.RouteTables[0]
170+
171+
// Remove all Gateway association
172+
for _, r := range rt.PropagatingVgws {
173+
log.Printf(
174+
"[INFO] Deleting VGW propagation from %s: %s",
175+
defaultRouteTableId, *r.GatewayId)
176+
_, err := conn.DisableVgwRoutePropagation(&ec2.DisableVgwRoutePropagationInput{
177+
RouteTableId: aws.String(defaultRouteTableId),
178+
GatewayId: r.GatewayId,
179+
})
180+
if err != nil {
181+
return err
182+
}
183+
}
184+
185+
// Delete all routes
186+
for _, r := range rt.Routes {
187+
// you cannot delete the local route
188+
if r.GatewayId != nil && *r.GatewayId == "local" {
189+
continue
190+
}
191+
log.Printf(
192+
"[INFO] Deleting route from %s: %s",
193+
defaultRouteTableId, *r.DestinationCidrBlock)
194+
_, err := conn.DeleteRoute(&ec2.DeleteRouteInput{
195+
RouteTableId: aws.String(defaultRouteTableId),
196+
DestinationCidrBlock: r.DestinationCidrBlock,
197+
})
198+
if err != nil {
199+
return err
200+
}
201+
}
202+
203+
return nil
204+
}

0 commit comments

Comments
 (0)