github.com/andresvia/terraform@v0.6.15-0.20160412045437-d51c75946785/builtin/providers/aws/resource_aws_route.go (about) 1 package aws 2 3 import ( 4 "errors" 5 "fmt" 6 "log" 7 8 "github.com/aws/aws-sdk-go/aws" 9 "github.com/aws/aws-sdk-go/service/ec2" 10 "github.com/hashicorp/terraform/helper/hashcode" 11 "github.com/hashicorp/terraform/helper/schema" 12 ) 13 14 // How long to sleep if a limit-exceeded event happens 15 var routeTargetValidationError = errors.New("Error: more than 1 target specified. Only 1 of gateway_id" + 16 "nat_gateway_id, instance_id, network_interface_id, route_table_id or" + 17 "vpc_peering_connection_id is allowed.") 18 19 // AWS Route resource Schema declaration 20 func resourceAwsRoute() *schema.Resource { 21 return &schema.Resource{ 22 Create: resourceAwsRouteCreate, 23 Read: resourceAwsRouteRead, 24 Update: resourceAwsRouteUpdate, 25 Delete: resourceAwsRouteDelete, 26 Exists: resourceAwsRouteExists, 27 28 Schema: map[string]*schema.Schema{ 29 "destination_cidr_block": &schema.Schema{ 30 Type: schema.TypeString, 31 Required: true, 32 ForceNew: true, 33 }, 34 35 "destination_prefix_list_id": &schema.Schema{ 36 Type: schema.TypeString, 37 Computed: true, 38 }, 39 40 "gateway_id": &schema.Schema{ 41 Type: schema.TypeString, 42 Optional: true, 43 Computed: true, 44 }, 45 46 "nat_gateway_id": &schema.Schema{ 47 Type: schema.TypeString, 48 Optional: true, 49 Computed: true, 50 }, 51 52 "instance_id": &schema.Schema{ 53 Type: schema.TypeString, 54 Optional: true, 55 Computed: true, 56 }, 57 58 "instance_owner_id": &schema.Schema{ 59 Type: schema.TypeString, 60 Computed: true, 61 }, 62 63 "network_interface_id": &schema.Schema{ 64 Type: schema.TypeString, 65 Optional: true, 66 Computed: true, 67 }, 68 69 "origin": &schema.Schema{ 70 Type: schema.TypeString, 71 Computed: true, 72 }, 73 74 "state": &schema.Schema{ 75 Type: schema.TypeString, 76 Computed: true, 77 }, 78 79 "route_table_id": &schema.Schema{ 80 Type: schema.TypeString, 81 Required: true, 82 }, 83 84 "vpc_peering_connection_id": &schema.Schema{ 85 Type: schema.TypeString, 86 Optional: true, 87 }, 88 }, 89 } 90 } 91 92 func resourceAwsRouteCreate(d *schema.ResourceData, meta interface{}) error { 93 conn := meta.(*AWSClient).ec2conn 94 var numTargets int 95 var setTarget string 96 allowedTargets := []string{ 97 "gateway_id", 98 "nat_gateway_id", 99 "instance_id", 100 "network_interface_id", 101 "vpc_peering_connection_id", 102 } 103 104 // Check if more than 1 target is specified 105 for _, target := range allowedTargets { 106 if len(d.Get(target).(string)) > 0 { 107 numTargets++ 108 setTarget = target 109 } 110 } 111 112 if numTargets > 1 { 113 return routeTargetValidationError 114 } 115 116 createOpts := &ec2.CreateRouteInput{} 117 // Formulate CreateRouteInput based on the target type 118 switch setTarget { 119 case "gateway_id": 120 createOpts = &ec2.CreateRouteInput{ 121 RouteTableId: aws.String(d.Get("route_table_id").(string)), 122 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 123 GatewayId: aws.String(d.Get("gateway_id").(string)), 124 } 125 case "nat_gateway_id": 126 createOpts = &ec2.CreateRouteInput{ 127 RouteTableId: aws.String(d.Get("route_table_id").(string)), 128 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 129 NatGatewayId: aws.String(d.Get("nat_gateway_id").(string)), 130 } 131 case "instance_id": 132 createOpts = &ec2.CreateRouteInput{ 133 RouteTableId: aws.String(d.Get("route_table_id").(string)), 134 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 135 InstanceId: aws.String(d.Get("instance_id").(string)), 136 } 137 case "network_interface_id": 138 createOpts = &ec2.CreateRouteInput{ 139 RouteTableId: aws.String(d.Get("route_table_id").(string)), 140 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 141 NetworkInterfaceId: aws.String(d.Get("network_interface_id").(string)), 142 } 143 case "vpc_peering_connection_id": 144 createOpts = &ec2.CreateRouteInput{ 145 RouteTableId: aws.String(d.Get("route_table_id").(string)), 146 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 147 VpcPeeringConnectionId: aws.String(d.Get("vpc_peering_connection_id").(string)), 148 } 149 default: 150 return fmt.Errorf("Error: invalid target type specified.") 151 } 152 log.Printf("[DEBUG] Route create config: %s", createOpts) 153 154 // Create the route 155 _, err := conn.CreateRoute(createOpts) 156 if err != nil { 157 return fmt.Errorf("Error creating route: %s", err) 158 } 159 160 route, err := findResourceRoute(conn, d.Get("route_table_id").(string), d.Get("destination_cidr_block").(string)) 161 if err != nil { 162 return err 163 } 164 165 d.SetId(routeIDHash(d, route)) 166 167 return resourceAwsRouteRead(d, meta) 168 } 169 170 func resourceAwsRouteRead(d *schema.ResourceData, meta interface{}) error { 171 conn := meta.(*AWSClient).ec2conn 172 route, err := findResourceRoute(conn, d.Get("route_table_id").(string), d.Get("destination_cidr_block").(string)) 173 if err != nil { 174 return err 175 } 176 177 d.Set("destination_prefix_list_id", route.DestinationPrefixListId) 178 d.Set("gateway_id", route.GatewayId) 179 d.Set("nat_gateway_id", route.NatGatewayId) 180 d.Set("instance_id", route.InstanceId) 181 d.Set("instance_owner_id", route.InstanceOwnerId) 182 d.Set("network_interface_id", route.NetworkInterfaceId) 183 d.Set("origin", route.Origin) 184 d.Set("state", route.State) 185 d.Set("vpc_peering_connection_id", route.VpcPeeringConnectionId) 186 187 return nil 188 } 189 190 func resourceAwsRouteUpdate(d *schema.ResourceData, meta interface{}) error { 191 conn := meta.(*AWSClient).ec2conn 192 var numTargets int 193 var setTarget string 194 allowedTargets := []string{ 195 "gateway_id", 196 "nat_gateway_id", 197 "instance_id", 198 "network_interface_id", 199 "vpc_peering_connection_id", 200 } 201 replaceOpts := &ec2.ReplaceRouteInput{} 202 203 // Check if more than 1 target is specified 204 for _, target := range allowedTargets { 205 if len(d.Get(target).(string)) > 0 { 206 numTargets++ 207 setTarget = target 208 } 209 } 210 211 if numTargets > 1 { 212 return routeTargetValidationError 213 } 214 215 // Formulate ReplaceRouteInput based on the target type 216 switch setTarget { 217 case "gateway_id": 218 replaceOpts = &ec2.ReplaceRouteInput{ 219 RouteTableId: aws.String(d.Get("route_table_id").(string)), 220 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 221 GatewayId: aws.String(d.Get("gateway_id").(string)), 222 } 223 case "nat_gateway_id": 224 replaceOpts = &ec2.ReplaceRouteInput{ 225 RouteTableId: aws.String(d.Get("route_table_id").(string)), 226 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 227 NatGatewayId: aws.String(d.Get("nat_gateway_id").(string)), 228 } 229 case "instance_id": 230 replaceOpts = &ec2.ReplaceRouteInput{ 231 RouteTableId: aws.String(d.Get("route_table_id").(string)), 232 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 233 InstanceId: aws.String(d.Get("instance_id").(string)), 234 //NOOP: Ensure we don't blow away network interface id that is set after instance is launched 235 NetworkInterfaceId: aws.String(d.Get("network_interface_id").(string)), 236 } 237 case "network_interface_id": 238 replaceOpts = &ec2.ReplaceRouteInput{ 239 RouteTableId: aws.String(d.Get("route_table_id").(string)), 240 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 241 NetworkInterfaceId: aws.String(d.Get("network_interface_id").(string)), 242 } 243 case "vpc_peering_connection_id": 244 replaceOpts = &ec2.ReplaceRouteInput{ 245 RouteTableId: aws.String(d.Get("route_table_id").(string)), 246 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 247 VpcPeeringConnectionId: aws.String(d.Get("vpc_peering_connection_id").(string)), 248 } 249 default: 250 return fmt.Errorf("Error: invalid target type specified.") 251 } 252 log.Printf("[DEBUG] Route replace config: %s", replaceOpts) 253 254 // Replace the route 255 _, err := conn.ReplaceRoute(replaceOpts) 256 if err != nil { 257 return err 258 } 259 260 return nil 261 } 262 263 func resourceAwsRouteDelete(d *schema.ResourceData, meta interface{}) error { 264 conn := meta.(*AWSClient).ec2conn 265 266 deleteOpts := &ec2.DeleteRouteInput{ 267 RouteTableId: aws.String(d.Get("route_table_id").(string)), 268 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 269 } 270 log.Printf("[DEBUG] Route delete opts: %s", deleteOpts) 271 272 resp, err := conn.DeleteRoute(deleteOpts) 273 log.Printf("[DEBUG] Route delete result: %s", resp) 274 if err != nil { 275 return err 276 } 277 278 d.SetId("") 279 return nil 280 } 281 282 func resourceAwsRouteExists(d *schema.ResourceData, meta interface{}) (bool, error) { 283 conn := meta.(*AWSClient).ec2conn 284 routeTableId := d.Get("route_table_id").(string) 285 286 findOpts := &ec2.DescribeRouteTablesInput{ 287 RouteTableIds: []*string{&routeTableId}, 288 } 289 290 res, err := conn.DescribeRouteTables(findOpts) 291 if err != nil { 292 return false, fmt.Errorf("Error while checking if route exists: %s", err) 293 } 294 295 if len(res.RouteTables) < 1 || res.RouteTables[0] == nil { 296 log.Printf("[WARN] Route table %s is gone, so route does not exist.", 297 routeTableId) 298 return false, nil 299 } 300 301 cidr := d.Get("destination_cidr_block").(string) 302 for _, route := range (*res.RouteTables[0]).Routes { 303 if route.DestinationCidrBlock != nil && *route.DestinationCidrBlock == cidr { 304 return true, nil 305 } 306 } 307 308 return false, nil 309 } 310 311 // Create an ID for a route 312 func routeIDHash(d *schema.ResourceData, r *ec2.Route) string { 313 return fmt.Sprintf("r-%s%d", d.Get("route_table_id").(string), hashcode.String(*r.DestinationCidrBlock)) 314 } 315 316 // Helper: retrieve a route 317 func findResourceRoute(conn *ec2.EC2, rtbid string, cidr string) (*ec2.Route, error) { 318 routeTableID := rtbid 319 320 findOpts := &ec2.DescribeRouteTablesInput{ 321 RouteTableIds: []*string{&routeTableID}, 322 } 323 324 resp, err := conn.DescribeRouteTables(findOpts) 325 if err != nil { 326 return nil, err 327 } 328 329 if len(resp.RouteTables) < 1 || resp.RouteTables[0] == nil { 330 return nil, fmt.Errorf("Route table %s is gone, so route does not exist.", 331 routeTableID) 332 } 333 334 for _, route := range (*resp.RouteTables[0]).Routes { 335 if *route.DestinationCidrBlock == cidr { 336 return route, nil 337 } 338 } 339 340 return nil, fmt.Errorf(` 341 error finding matching route for Route table (%s) and destination CIDR block (%s)`, 342 rtbid, cidr) 343 }