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  }