github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/aws/resource_aws_vpc_endpoint.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  
     7  	"github.com/aws/aws-sdk-go/aws"
     8  	"github.com/aws/aws-sdk-go/aws/awserr"
     9  	"github.com/aws/aws-sdk-go/service/ec2"
    10  	"github.com/hashicorp/errwrap"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  )
    13  
    14  func resourceAwsVpcEndpoint() *schema.Resource {
    15  	return &schema.Resource{
    16  		Create: resourceAwsVPCEndpointCreate,
    17  		Read:   resourceAwsVPCEndpointRead,
    18  		Update: resourceAwsVPCEndpointUpdate,
    19  		Delete: resourceAwsVPCEndpointDelete,
    20  		Importer: &schema.ResourceImporter{
    21  			State: schema.ImportStatePassthrough,
    22  		},
    23  
    24  		Schema: map[string]*schema.Schema{
    25  			"policy": &schema.Schema{
    26  				Type:         schema.TypeString,
    27  				Optional:     true,
    28  				Computed:     true,
    29  				ValidateFunc: validateJsonString,
    30  				StateFunc: func(v interface{}) string {
    31  					json, _ := normalizeJsonString(v)
    32  					return json
    33  				},
    34  			},
    35  			"vpc_id": &schema.Schema{
    36  				Type:     schema.TypeString,
    37  				Required: true,
    38  				ForceNew: true,
    39  			},
    40  			"service_name": &schema.Schema{
    41  				Type:     schema.TypeString,
    42  				Required: true,
    43  				ForceNew: true,
    44  			},
    45  			"route_table_ids": &schema.Schema{
    46  				Type:     schema.TypeSet,
    47  				Optional: true,
    48  				Computed: true,
    49  				Elem:     &schema.Schema{Type: schema.TypeString},
    50  				Set:      schema.HashString,
    51  			},
    52  			"prefix_list_id": &schema.Schema{
    53  				Type:     schema.TypeString,
    54  				Computed: true,
    55  			},
    56  			"cidr_blocks": &schema.Schema{
    57  				Type:     schema.TypeList,
    58  				Computed: true,
    59  				Elem:     &schema.Schema{Type: schema.TypeString},
    60  			},
    61  		},
    62  	}
    63  }
    64  
    65  func resourceAwsVPCEndpointCreate(d *schema.ResourceData, meta interface{}) error {
    66  	conn := meta.(*AWSClient).ec2conn
    67  	input := &ec2.CreateVpcEndpointInput{
    68  		VpcId:       aws.String(d.Get("vpc_id").(string)),
    69  		ServiceName: aws.String(d.Get("service_name").(string)),
    70  	}
    71  
    72  	if v, ok := d.GetOk("route_table_ids"); ok {
    73  		list := v.(*schema.Set).List()
    74  		if len(list) > 0 {
    75  			input.RouteTableIds = expandStringList(list)
    76  		}
    77  	}
    78  
    79  	if v, ok := d.GetOk("policy"); ok {
    80  		policy, err := normalizeJsonString(v)
    81  		if err != nil {
    82  			return errwrap.Wrapf("policy contains an invalid JSON: {{err}}", err)
    83  		}
    84  		input.PolicyDocument = aws.String(policy)
    85  	}
    86  
    87  	log.Printf("[DEBUG] Creating VPC Endpoint: %#v", input)
    88  	output, err := conn.CreateVpcEndpoint(input)
    89  	if err != nil {
    90  		return fmt.Errorf("Error creating VPC Endpoint: %s", err)
    91  	}
    92  	log.Printf("[DEBUG] VPC Endpoint %q created.", *output.VpcEndpoint.VpcEndpointId)
    93  
    94  	d.SetId(*output.VpcEndpoint.VpcEndpointId)
    95  
    96  	return resourceAwsVPCEndpointRead(d, meta)
    97  }
    98  
    99  func resourceAwsVPCEndpointRead(d *schema.ResourceData, meta interface{}) error {
   100  	conn := meta.(*AWSClient).ec2conn
   101  	input := &ec2.DescribeVpcEndpointsInput{
   102  		VpcEndpointIds: []*string{aws.String(d.Id())},
   103  	}
   104  
   105  	log.Printf("[DEBUG] Reading VPC Endpoint: %q", d.Id())
   106  	output, err := conn.DescribeVpcEndpoints(input)
   107  
   108  	if err != nil {
   109  		ec2err, ok := err.(awserr.Error)
   110  		if !ok {
   111  			return fmt.Errorf("Error reading VPC Endpoint: %s", err.Error())
   112  		}
   113  
   114  		if ec2err.Code() == "InvalidVpcEndpointId.NotFound" {
   115  			log.Printf("[WARN] VPC Endpoint (%s) not found, removing from state", d.Id())
   116  			d.SetId("")
   117  			return nil
   118  		}
   119  
   120  		return fmt.Errorf("Error reading VPC Endpoint: %s", err.Error())
   121  	}
   122  
   123  	if len(output.VpcEndpoints) != 1 {
   124  		return fmt.Errorf("There's no unique VPC Endpoint, but %d endpoints: %#v",
   125  			len(output.VpcEndpoints), output.VpcEndpoints)
   126  	}
   127  
   128  	vpce := output.VpcEndpoints[0]
   129  
   130  	// A VPC Endpoint is associated with exactly one prefix list name (also called Service Name).
   131  	// The prefix list ID can be used in security groups, so retrieve it to support that capability.
   132  	prefixListServiceName := *vpce.ServiceName
   133  	prefixListInput := &ec2.DescribePrefixListsInput{
   134  		Filters: []*ec2.Filter{
   135  			{Name: aws.String("prefix-list-name"), Values: []*string{aws.String(prefixListServiceName)}},
   136  		},
   137  	}
   138  
   139  	log.Printf("[DEBUG] Reading VPC Endpoint prefix list: %s", prefixListServiceName)
   140  	prefixListsOutput, err := conn.DescribePrefixLists(prefixListInput)
   141  
   142  	if err != nil {
   143  		_, ok := err.(awserr.Error)
   144  		if !ok {
   145  			return fmt.Errorf("Error reading VPC Endpoint prefix list: %s", err.Error())
   146  		}
   147  	}
   148  
   149  	if len(prefixListsOutput.PrefixLists) != 1 {
   150  		return fmt.Errorf("There are multiple prefix lists associated with the service name '%s'. Unexpected", prefixListServiceName)
   151  	}
   152  
   153  	policy, err := normalizeJsonString(*vpce.PolicyDocument)
   154  	if err != nil {
   155  		return errwrap.Wrapf("policy contains an invalid JSON: {{err}}", err)
   156  	}
   157  
   158  	d.Set("vpc_id", vpce.VpcId)
   159  	d.Set("policy", policy)
   160  	d.Set("service_name", vpce.ServiceName)
   161  	if err := d.Set("route_table_ids", aws.StringValueSlice(vpce.RouteTableIds)); err != nil {
   162  		return err
   163  	}
   164  	pl := prefixListsOutput.PrefixLists[0]
   165  	d.Set("prefix_list_id", pl.PrefixListId)
   166  	d.Set("cidr_blocks", aws.StringValueSlice(pl.Cidrs))
   167  
   168  	return nil
   169  }
   170  
   171  func resourceAwsVPCEndpointUpdate(d *schema.ResourceData, meta interface{}) error {
   172  	conn := meta.(*AWSClient).ec2conn
   173  	input := &ec2.ModifyVpcEndpointInput{
   174  		VpcEndpointId: aws.String(d.Id()),
   175  	}
   176  
   177  	if d.HasChange("route_table_ids") {
   178  		o, n := d.GetChange("route_table_ids")
   179  		os := o.(*schema.Set)
   180  		ns := n.(*schema.Set)
   181  
   182  		add := expandStringList(ns.Difference(os).List())
   183  		if len(add) > 0 {
   184  			input.AddRouteTableIds = add
   185  		}
   186  
   187  		remove := expandStringList(os.Difference(ns).List())
   188  		if len(remove) > 0 {
   189  			input.RemoveRouteTableIds = remove
   190  		}
   191  	}
   192  
   193  	if d.HasChange("policy") {
   194  		policy, err := normalizeJsonString(d.Get("policy"))
   195  		if err != nil {
   196  			return errwrap.Wrapf("policy contains an invalid JSON: {{err}}", err)
   197  		}
   198  		input.PolicyDocument = aws.String(policy)
   199  	}
   200  
   201  	log.Printf("[DEBUG] Updating VPC Endpoint: %#v", input)
   202  	_, err := conn.ModifyVpcEndpoint(input)
   203  	if err != nil {
   204  		return fmt.Errorf("Error updating VPC Endpoint: %s", err)
   205  	}
   206  	log.Printf("[DEBUG] VPC Endpoint %q updated", input.VpcEndpointId)
   207  
   208  	return resourceAwsVPCEndpointRead(d, meta)
   209  }
   210  
   211  func resourceAwsVPCEndpointDelete(d *schema.ResourceData, meta interface{}) error {
   212  	conn := meta.(*AWSClient).ec2conn
   213  	input := &ec2.DeleteVpcEndpointsInput{
   214  		VpcEndpointIds: []*string{aws.String(d.Id())},
   215  	}
   216  
   217  	log.Printf("[DEBUG] Deleting VPC Endpoint: %#v", input)
   218  	_, err := conn.DeleteVpcEndpoints(input)
   219  
   220  	if err != nil {
   221  		ec2err, ok := err.(awserr.Error)
   222  		if !ok {
   223  			return fmt.Errorf("Error deleting VPC Endpoint: %s", err.Error())
   224  		}
   225  
   226  		if ec2err.Code() == "InvalidVpcEndpointId.NotFound" {
   227  			log.Printf("[DEBUG] VPC Endpoint %q is already gone", d.Id())
   228  		} else {
   229  			return fmt.Errorf("Error deleting VPC Endpoint: %s", err.Error())
   230  		}
   231  	}
   232  
   233  	log.Printf("[DEBUG] VPC Endpoint %q deleted", d.Id())
   234  	d.SetId("")
   235  
   236  	return nil
   237  }