github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/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 }