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