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  }