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