github.com/leeprovoost/terraform@v0.6.10-0.20160119085442-96f3f76118e7/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 }, 44 45 "nat_gateway_id": &schema.Schema{ 46 Type: schema.TypeString, 47 Optional: true, 48 }, 49 50 "instance_id": &schema.Schema{ 51 Type: schema.TypeString, 52 Optional: true, 53 }, 54 55 "instance_owner_id": &schema.Schema{ 56 Type: schema.TypeString, 57 Computed: true, 58 }, 59 60 "network_interface_id": &schema.Schema{ 61 Type: schema.TypeString, 62 Optional: true, 63 }, 64 65 "origin": &schema.Schema{ 66 Type: schema.TypeString, 67 Computed: true, 68 }, 69 70 "state": &schema.Schema{ 71 Type: schema.TypeString, 72 Computed: true, 73 }, 74 75 "route_table_id": &schema.Schema{ 76 Type: schema.TypeString, 77 Required: true, 78 }, 79 80 "vpc_peering_connection_id": &schema.Schema{ 81 Type: schema.TypeString, 82 Optional: true, 83 }, 84 }, 85 } 86 } 87 88 func resourceAwsRouteCreate(d *schema.ResourceData, meta interface{}) error { 89 conn := meta.(*AWSClient).ec2conn 90 var numTargets int 91 var setTarget string 92 allowedTargets := []string{ 93 "gateway_id", 94 "nat_gateway_id", 95 "instance_id", 96 "network_interface_id", 97 "vpc_peering_connection_id", 98 } 99 100 // Check if more than 1 target is specified 101 for _, target := range allowedTargets { 102 if len(d.Get(target).(string)) > 0 { 103 numTargets++ 104 setTarget = target 105 } 106 } 107 108 if numTargets > 1 { 109 return routeTargetValidationError 110 } 111 112 createOpts := &ec2.CreateRouteInput{} 113 // Formulate CreateRouteInput based on the target type 114 switch setTarget { 115 case "gateway_id": 116 createOpts = &ec2.CreateRouteInput{ 117 RouteTableId: aws.String(d.Get("route_table_id").(string)), 118 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 119 GatewayId: aws.String(d.Get("gateway_id").(string)), 120 } 121 case "nat_gateway_id": 122 createOpts = &ec2.CreateRouteInput{ 123 RouteTableId: aws.String(d.Get("route_table_id").(string)), 124 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 125 NatGatewayId: aws.String(d.Get("nat_gateway_id").(string)), 126 } 127 case "instance_id": 128 createOpts = &ec2.CreateRouteInput{ 129 RouteTableId: aws.String(d.Get("route_table_id").(string)), 130 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 131 InstanceId: aws.String(d.Get("instance_id").(string)), 132 } 133 case "network_interface_id": 134 createOpts = &ec2.CreateRouteInput{ 135 RouteTableId: aws.String(d.Get("route_table_id").(string)), 136 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 137 NetworkInterfaceId: aws.String(d.Get("network_interface_id").(string)), 138 } 139 case "vpc_peering_connection_id": 140 createOpts = &ec2.CreateRouteInput{ 141 RouteTableId: aws.String(d.Get("route_table_id").(string)), 142 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 143 VpcPeeringConnectionId: aws.String(d.Get("vpc_peering_connection_id").(string)), 144 } 145 default: 146 return fmt.Errorf("Error: invalid target type specified.") 147 } 148 log.Printf("[DEBUG] Route create config: %s", createOpts) 149 150 // Create the route 151 _, err := conn.CreateRoute(createOpts) 152 if err != nil { 153 return fmt.Errorf("Error creating route: %s", err) 154 } 155 156 route, err := findResourceRoute(conn, d.Get("route_table_id").(string), d.Get("destination_cidr_block").(string)) 157 if err != nil { 158 return err 159 } 160 161 d.SetId(routeIDHash(d, route)) 162 163 return resourceAwsRouteRead(d, meta) 164 } 165 166 func resourceAwsRouteRead(d *schema.ResourceData, meta interface{}) error { 167 conn := meta.(*AWSClient).ec2conn 168 route, err := findResourceRoute(conn, d.Get("route_table_id").(string), d.Get("destination_cidr_block").(string)) 169 if err != nil { 170 return err 171 } 172 173 d.Set("destination_prefix_list_id", route.DestinationPrefixListId) 174 d.Set("gateway_id", route.GatewayId) 175 d.Set("nat_gateway_id", route.NatGatewayId) 176 d.Set("instance_id", route.InstanceId) 177 d.Set("instance_owner_id", route.InstanceOwnerId) 178 d.Set("network_interface_id", route.NetworkInterfaceId) 179 d.Set("origin", route.Origin) 180 d.Set("state", route.State) 181 d.Set("vpc_peering_connection_id", route.VpcPeeringConnectionId) 182 183 return nil 184 } 185 186 func resourceAwsRouteUpdate(d *schema.ResourceData, meta interface{}) error { 187 conn := meta.(*AWSClient).ec2conn 188 var numTargets int 189 var setTarget string 190 allowedTargets := []string{ 191 "gateway_id", 192 "nat_gateway_id", 193 "instance_id", 194 "network_interface_id", 195 "vpc_peering_connection_id", 196 } 197 replaceOpts := &ec2.ReplaceRouteInput{} 198 199 // Check if more than 1 target is specified 200 for _, target := range allowedTargets { 201 if len(d.Get(target).(string)) > 0 { 202 numTargets++ 203 setTarget = target 204 } 205 } 206 207 if numTargets > 1 { 208 return routeTargetValidationError 209 } 210 211 // Formulate ReplaceRouteInput based on the target type 212 switch setTarget { 213 case "gateway_id": 214 replaceOpts = &ec2.ReplaceRouteInput{ 215 RouteTableId: aws.String(d.Get("route_table_id").(string)), 216 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 217 GatewayId: aws.String(d.Get("gateway_id").(string)), 218 } 219 case "nat_gateway_id": 220 replaceOpts = &ec2.ReplaceRouteInput{ 221 RouteTableId: aws.String(d.Get("route_table_id").(string)), 222 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 223 NatGatewayId: aws.String(d.Get("nat_gateway_id").(string)), 224 } 225 case "instance_id": 226 replaceOpts = &ec2.ReplaceRouteInput{ 227 RouteTableId: aws.String(d.Get("route_table_id").(string)), 228 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 229 InstanceId: aws.String(d.Get("instance_id").(string)), 230 //NOOP: Ensure we don't blow away network interface id that is set after instance is launched 231 NetworkInterfaceId: aws.String(d.Get("network_interface_id").(string)), 232 } 233 case "network_interface_id": 234 replaceOpts = &ec2.ReplaceRouteInput{ 235 RouteTableId: aws.String(d.Get("route_table_id").(string)), 236 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 237 NetworkInterfaceId: aws.String(d.Get("network_interface_id").(string)), 238 } 239 case "vpc_peering_connection_id": 240 replaceOpts = &ec2.ReplaceRouteInput{ 241 RouteTableId: aws.String(d.Get("route_table_id").(string)), 242 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 243 VpcPeeringConnectionId: aws.String(d.Get("vpc_peering_connection_id").(string)), 244 } 245 default: 246 return fmt.Errorf("Error: invalid target type specified.") 247 } 248 log.Printf("[DEBUG] Route replace config: %s", replaceOpts) 249 250 // Replace the route 251 _, err := conn.ReplaceRoute(replaceOpts) 252 if err != nil { 253 return err 254 } 255 256 return nil 257 } 258 259 func resourceAwsRouteDelete(d *schema.ResourceData, meta interface{}) error { 260 conn := meta.(*AWSClient).ec2conn 261 262 deleteOpts := &ec2.DeleteRouteInput{ 263 RouteTableId: aws.String(d.Get("route_table_id").(string)), 264 DestinationCidrBlock: aws.String(d.Get("destination_cidr_block").(string)), 265 } 266 log.Printf("[DEBUG] Route delete opts: %s", deleteOpts) 267 268 resp, err := conn.DeleteRoute(deleteOpts) 269 log.Printf("[DEBUG] Route delete result: %s", resp) 270 if err != nil { 271 return err 272 } 273 274 d.SetId("") 275 return nil 276 } 277 278 func resourceAwsRouteExists(d *schema.ResourceData, meta interface{}) (bool, error) { 279 conn := meta.(*AWSClient).ec2conn 280 routeTableId := d.Get("route_table_id").(string) 281 282 findOpts := &ec2.DescribeRouteTablesInput{ 283 RouteTableIds: []*string{&routeTableId}, 284 } 285 286 res, err := conn.DescribeRouteTables(findOpts) 287 if err != nil { 288 return false, err 289 } 290 291 cidr := d.Get("destination_cidr_block").(string) 292 for _, route := range (*res.RouteTables[0]).Routes { 293 if *route.DestinationCidrBlock == cidr { 294 return true, nil 295 } 296 } 297 298 return false, nil 299 } 300 301 // Create an ID for a route 302 func routeIDHash(d *schema.ResourceData, r *ec2.Route) string { 303 return fmt.Sprintf("r-%s%d", d.Get("route_table_id").(string), hashcode.String(*r.DestinationCidrBlock)) 304 } 305 306 // Helper: retrieve a route 307 func findResourceRoute(conn *ec2.EC2, rtbid string, cidr string) (*ec2.Route, error) { 308 routeTableID := rtbid 309 310 findOpts := &ec2.DescribeRouteTablesInput{ 311 RouteTableIds: []*string{&routeTableID}, 312 } 313 314 resp, err := conn.DescribeRouteTables(findOpts) 315 if err != nil { 316 return nil, err 317 } 318 319 for _, route := range (*resp.RouteTables[0]).Routes { 320 if *route.DestinationCidrBlock == cidr { 321 return route, nil 322 } 323 } 324 325 return nil, nil 326 }