github.com/renier/terraform@v0.7.8-0.20161024133817-eb8a9ef5471a/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 Elem: &schema.Schema{Type: schema.TypeString}, 49 Set: schema.HashString, 50 }, 51 "prefix_list_id": &schema.Schema{ 52 Type: schema.TypeString, 53 Computed: true, 54 }, 55 }, 56 } 57 } 58 59 func resourceAwsVPCEndpointCreate(d *schema.ResourceData, meta interface{}) error { 60 conn := meta.(*AWSClient).ec2conn 61 input := &ec2.CreateVpcEndpointInput{ 62 VpcId: aws.String(d.Get("vpc_id").(string)), 63 ServiceName: aws.String(d.Get("service_name").(string)), 64 } 65 66 if v, ok := d.GetOk("route_table_ids"); ok { 67 list := v.(*schema.Set).List() 68 if len(list) > 0 { 69 input.RouteTableIds = expandStringList(list) 70 } 71 } 72 73 if v, ok := d.GetOk("policy"); ok { 74 policy, err := normalizeJsonString(v) 75 if err != nil { 76 return errwrap.Wrapf("policy contains an invalid JSON: {{err}}", err) 77 } 78 input.PolicyDocument = aws.String(policy) 79 } 80 81 log.Printf("[DEBUG] Creating VPC Endpoint: %#v", input) 82 output, err := conn.CreateVpcEndpoint(input) 83 if err != nil { 84 return fmt.Errorf("Error creating VPC Endpoint: %s", err) 85 } 86 log.Printf("[DEBUG] VPC Endpoint %q created.", *output.VpcEndpoint.VpcEndpointId) 87 88 d.SetId(*output.VpcEndpoint.VpcEndpointId) 89 90 return resourceAwsVPCEndpointRead(d, meta) 91 } 92 93 func resourceAwsVPCEndpointRead(d *schema.ResourceData, meta interface{}) error { 94 conn := meta.(*AWSClient).ec2conn 95 input := &ec2.DescribeVpcEndpointsInput{ 96 VpcEndpointIds: []*string{aws.String(d.Id())}, 97 } 98 99 log.Printf("[DEBUG] Reading VPC Endpoint: %q", d.Id()) 100 output, err := conn.DescribeVpcEndpoints(input) 101 102 if err != nil { 103 ec2err, ok := err.(awserr.Error) 104 if !ok { 105 return fmt.Errorf("Error reading VPC Endpoint: %s", err.Error()) 106 } 107 108 if ec2err.Code() == "InvalidVpcEndpointId.NotFound" { 109 return nil 110 } 111 112 return fmt.Errorf("Error reading VPC Endpoint: %s", err.Error()) 113 } 114 115 if len(output.VpcEndpoints) != 1 { 116 return fmt.Errorf("There's no unique VPC Endpoint, but %d endpoints: %#v", 117 len(output.VpcEndpoints), output.VpcEndpoints) 118 } 119 120 vpce := output.VpcEndpoints[0] 121 122 // A VPC Endpoint is associated with exactly one prefix list name (also called Service Name). 123 // The prefix list ID can be used in security groups, so retrieve it to support that capability. 124 prefixListServiceName := *vpce.ServiceName 125 prefixListInput := &ec2.DescribePrefixListsInput{ 126 Filters: []*ec2.Filter{ 127 {Name: aws.String("prefix-list-name"), Values: []*string{aws.String(prefixListServiceName)}}, 128 }, 129 } 130 131 log.Printf("[DEBUG] Reading VPC Endpoint prefix list: %s", prefixListServiceName) 132 prefixListsOutput, err := conn.DescribePrefixLists(prefixListInput) 133 134 if err != nil { 135 _, ok := err.(awserr.Error) 136 if !ok { 137 return fmt.Errorf("Error reading VPC Endpoint prefix list: %s", err.Error()) 138 } 139 } 140 141 if len(prefixListsOutput.PrefixLists) != 1 { 142 return fmt.Errorf("There are multiple prefix lists associated with the service name '%s'. Unexpected", prefixListServiceName) 143 } 144 145 policy, err := normalizeJsonString(*vpce.PolicyDocument) 146 if err != nil { 147 return errwrap.Wrapf("policy contains an invalid JSON: {{err}}", err) 148 } 149 150 d.Set("vpc_id", vpce.VpcId) 151 d.Set("policy", policy) 152 d.Set("service_name", vpce.ServiceName) 153 if err := d.Set("route_table_ids", aws.StringValueSlice(vpce.RouteTableIds)); err != nil { 154 return err 155 } 156 d.Set("prefix_list_id", prefixListsOutput.PrefixLists[0].PrefixListId) 157 158 return nil 159 } 160 161 func resourceAwsVPCEndpointUpdate(d *schema.ResourceData, meta interface{}) error { 162 conn := meta.(*AWSClient).ec2conn 163 input := &ec2.ModifyVpcEndpointInput{ 164 VpcEndpointId: aws.String(d.Id()), 165 } 166 167 if d.HasChange("route_table_ids") { 168 o, n := d.GetChange("route_table_ids") 169 os := o.(*schema.Set) 170 ns := n.(*schema.Set) 171 172 add := expandStringList(ns.Difference(os).List()) 173 if len(add) > 0 { 174 input.AddRouteTableIds = add 175 } 176 177 remove := expandStringList(os.Difference(ns).List()) 178 if len(remove) > 0 { 179 input.RemoveRouteTableIds = remove 180 } 181 } 182 183 if d.HasChange("policy") { 184 policy, err := normalizeJsonString(d.Get("policy")) 185 if err != nil { 186 return errwrap.Wrapf("policy contains an invalid JSON: {{err}}", err) 187 } 188 input.PolicyDocument = aws.String(policy) 189 } 190 191 log.Printf("[DEBUG] Updating VPC Endpoint: %#v", input) 192 _, err := conn.ModifyVpcEndpoint(input) 193 if err != nil { 194 return fmt.Errorf("Error updating VPC Endpoint: %s", err) 195 } 196 log.Printf("[DEBUG] VPC Endpoint %q updated", input.VpcEndpointId) 197 198 return resourceAwsVPCEndpointRead(d, meta) 199 } 200 201 func resourceAwsVPCEndpointDelete(d *schema.ResourceData, meta interface{}) error { 202 conn := meta.(*AWSClient).ec2conn 203 input := &ec2.DeleteVpcEndpointsInput{ 204 VpcEndpointIds: []*string{aws.String(d.Id())}, 205 } 206 207 log.Printf("[DEBUG] Deleting VPC Endpoint: %#v", input) 208 _, err := conn.DeleteVpcEndpoints(input) 209 210 if err != nil { 211 ec2err, ok := err.(awserr.Error) 212 if !ok { 213 return fmt.Errorf("Error deleting VPC Endpoint: %s", err.Error()) 214 } 215 216 if ec2err.Code() == "InvalidVpcEndpointId.NotFound" { 217 log.Printf("[DEBUG] VPC Endpoint %q is already gone", d.Id()) 218 } else { 219 return fmt.Errorf("Error deleting VPC Endpoint: %s", err.Error()) 220 } 221 } 222 223 log.Printf("[DEBUG] VPC Endpoint %q deleted", d.Id()) 224 d.SetId("") 225 226 return nil 227 }