diff --git a/builtin/providers/aws/data_source_aws_vpc_endpoint.go b/builtin/providers/aws/data_source_aws_vpc_endpoint.go new file mode 100644 index 000000000..c15933129 --- /dev/null +++ b/builtin/providers/aws/data_source_aws_vpc_endpoint.go @@ -0,0 +1,103 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/terraform/helper/schema" +) + +func dataSourceAwsVpcEndpoint() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsVpcEndpointRead, + + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "state": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "vpc_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "service_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "policy": { + Type: schema.TypeString, + Computed: true, + }, + "route_table_ids": &schema.Schema{ + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + }, + } +} + +func dataSourceAwsVpcEndpointRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + log.Printf("[DEBUG] Reading VPC Endpoints.") + + req := &ec2.DescribeVpcEndpointsInput{} + + if id, ok := d.GetOk("id"); ok { + req.VpcEndpointIds = aws.StringSlice([]string{id.(string)}) + } + + req.Filters = buildEC2AttributeFilterList( + map[string]string{ + "vpc-endpoint-state": d.Get("state").(string), + "vpc-id": d.Get("vpc_id").(string), + "service-name": d.Get("service_name").(string), + }, + ) + if len(req.Filters) == 0 { + // Don't send an empty filters list; the EC2 API won't accept it. + req.Filters = nil + } + + resp, err := conn.DescribeVpcEndpoints(req) + if err != nil { + return err + } + if resp == nil || len(resp.VpcEndpoints) == 0 { + return fmt.Errorf("no matching VPC endpoint found") + } + if len(resp.VpcEndpoints) > 1 { + return fmt.Errorf("multiple VPC endpoints matched; use additional constraints to reduce matches to a single VPC endpoint") + } + + vpce := resp.VpcEndpoints[0] + policy, err := normalizeJsonString(*vpce.PolicyDocument) + if err != nil { + return errwrap.Wrapf("policy contains an invalid JSON: {{err}}", err) + } + + d.SetId(aws.StringValue(vpce.VpcEndpointId)) + d.Set("id", vpce.VpcEndpointId) + d.Set("state", vpce.State) + d.Set("vpc_id", vpce.VpcId) + d.Set("service_name", vpce.ServiceName) + d.Set("policy", policy) + if err := d.Set("route_table_ids", aws.StringValueSlice(vpce.RouteTableIds)); err != nil { + return err + } + + return nil +} diff --git a/builtin/providers/aws/data_source_aws_vpc_endpoint_test.go b/builtin/providers/aws/data_source_aws_vpc_endpoint_test.go new file mode 100644 index 000000000..e73d0be56 --- /dev/null +++ b/builtin/providers/aws/data_source_aws_vpc_endpoint_test.go @@ -0,0 +1,129 @@ +// make testacc TEST=./builtin/providers/aws/ TESTARGS='-run=TestAccDataSourceAwsVpcEndpoint_' +package aws + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccDataSourceAwsVpcEndpoint_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccDataSourceAwsVpcEndpointConfig, + Check: resource.ComposeTestCheckFunc( + testAccDataSourceAwsVpcEndpointCheckExists("data.aws_vpc_endpoint.s3"), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccDataSourceAwsVpcEndpoint_withRouteTable(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccDataSourceAwsVpcEndpointWithRouteTableConfig, + Check: resource.ComposeTestCheckFunc( + testAccDataSourceAwsVpcEndpointCheckExists("data.aws_vpc_endpoint.s3"), + resource.TestCheckResourceAttr( + "data.aws_vpc_endpoint.s3", "route_table_ids.#", "1"), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccDataSourceAwsVpcEndpointCheckExists(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("root module has no resource called %s", name) + } + + vpceRs, ok := s.RootModule().Resources["aws_vpc_endpoint.s3"] + if !ok { + return fmt.Errorf("can't find aws_vpc_endpoint.s3 in state") + } + + attr := rs.Primary.Attributes + + if attr["id"] != vpceRs.Primary.Attributes["id"] { + return fmt.Errorf( + "id is %s; want %s", + attr["id"], + vpceRs.Primary.Attributes["id"], + ) + } + + return nil + } +} + +const testAccDataSourceAwsVpcEndpointConfig = ` +provider "aws" { + region = "us-west-2" +} + +resource "aws_vpc" "foo" { + cidr_block = "10.1.0.0/16" + + tags { + Name = "terraform-testacc-vpc-endpoint-data-source-foo" + } +} + +resource "aws_vpc_endpoint" "s3" { + vpc_id = "${aws_vpc.foo.id}" + service_name = "com.amazonaws.us-west-2.s3" +} + +data "aws_vpc_endpoint" "s3" { + vpc_id = "${aws_vpc.foo.id}" + service_name = "com.amazonaws.us-west-2.s3" + state = "available" + + depends_on = ["aws_vpc_endpoint.s3"] +} +` + +const testAccDataSourceAwsVpcEndpointWithRouteTableConfig = ` +provider "aws" { + region = "us-west-2" +} + +resource "aws_vpc" "foo" { + cidr_block = "10.1.0.0/16" + + tags { + Name = "terraform-testacc-vpc-endpoint-data-source-foo" + } +} + +resource "aws_route_table" "rt" { + vpc_id = "${aws_vpc.foo.id}" +} + +resource "aws_vpc_endpoint" "s3" { + vpc_id = "${aws_vpc.foo.id}" + service_name = "com.amazonaws.us-west-2.s3" + route_table_ids = ["${aws_route_table.rt.id}"] +} + +data "aws_vpc_endpoint" "s3" { + vpc_id = "${aws_vpc.foo.id}" + service_name = "com.amazonaws.us-west-2.s3" + state = "available" + + depends_on = ["aws_vpc_endpoint.s3"] +} +` diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index 3a78893ae..0ac123351 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -181,6 +181,7 @@ func Provider() terraform.ResourceProvider { "aws_subnet": dataSourceAwsSubnet(), "aws_security_group": dataSourceAwsSecurityGroup(), "aws_vpc": dataSourceAwsVpc(), + "aws_vpc_endpoint": dataSourceAwsVpcEndpoint(), "aws_vpc_endpoint_service": dataSourceAwsVpcEndpointService(), "aws_vpc_peering_connection": dataSourceAwsVpcPeeringConnection(), }, diff --git a/website/source/docs/providers/aws/d/vpc_endpoint.html.markdown b/website/source/docs/providers/aws/d/vpc_endpoint.html.markdown new file mode 100644 index 000000000..fe75bb506 --- /dev/null +++ b/website/source/docs/providers/aws/d/vpc_endpoint.html.markdown @@ -0,0 +1,48 @@ +--- +layout: "aws" +page_title: "AWS: aws_vpc_endpoint" +sidebar_current: "docs-aws-datasource-vpc-endpoint" +description: |- + Provides details about a specific VPC endpoint. +--- + +# aws\_vpc\_endpoint + +The VPC Endpoint data source provides details about +a specific VPC endpoint. + +## Example Usage + +``` +# Declare the data source +data "aws_vpc_endpoint" "s3" { + vpc_id = "${aws_vpc.foo.id}" + service_name = "com.amazonaws.us-west-2.s3" +} + +resource "aws_vpc_endpoint_route_table_association" "private_s3" { + vpc_endpoint_id = "${data.aws_vpc_endpoint.s3.id}" + route_table_id = "${aws_route_table.private.id}" +} +``` + +## Argument Reference + +The arguments of this data source act as filters for querying the available VPC endpoints. +The given filters must match exactly one VPC endpoint whose data will be exported as attributes. + +* `id` - (Optional) The ID of the specific VPC Endpoint to retrieve. + +* `state` - (Optional) The state of the specific VPC Endpoint to retrieve. + +* `vpc_id` - (Optional) The ID of the VPC in which the specific VPC Endpoint is used. + +* `service_name` - (Optional) The AWS service name of the specific VPC Endpoint to retrieve. + +## Attributes Reference + +All of the argument attributes are also exported as result attributes. + +* `policy` - The policy document associated with the VPC Endpoint. + +* `route_table_ids` - One or more route tables associated with the VPC Endpoint. diff --git a/website/source/layouts/aws.erb b/website/source/layouts/aws.erb index 9adee3a60..6679e96ad 100644 --- a/website/source/layouts/aws.erb +++ b/website/source/layouts/aws.erb @@ -98,6 +98,9 @@ > aws_vpc + > + aws_vpc_endpoint + > aws_vpc_endpoint_service