From f91d18310120ea6c487a2f824ee8282a327dd439 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 6 Jun 2022 11:54:06 +0300 Subject: [PATCH 01/16] address type --- internal/service/ec2/vpc_endpoint.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/internal/service/ec2/vpc_endpoint.go b/internal/service/ec2/vpc_endpoint.go index bc03d302e04a..3576d3ef997c 100644 --- a/internal/service/ec2/vpc_endpoint.go +++ b/internal/service/ec2/vpc_endpoint.go @@ -65,6 +65,11 @@ func ResourceVPCEndpoint() *schema.Resource { }, }, }, + "ip_address_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(ec2.IpAddressType_Values(), false), + }, "network_interface_ids": { Type: schema.TypeSet, Computed: true, @@ -176,6 +181,10 @@ func resourceVPCEndpointCreate(d *schema.ResourceData, meta interface{}) error { req.PolicyDocument = aws.String(policy) } + if v, ok := d.GetOk("ip_address_type"); ok { + req.IpAddressType = aws.String(v.(string)) + } + setVPCEndpointCreateList(d, "route_table_ids", &req.RouteTableIds) setVPCEndpointCreateList(d, "subnet_ids", &req.SubnetIds) setVPCEndpointCreateList(d, "security_group_ids", &req.SecurityGroupIds) @@ -234,6 +243,7 @@ func resourceVPCEndpointRead(d *schema.ResourceData, meta interface{}) error { d.Set("service_name", serviceName) d.Set("state", vpce.State) d.Set("vpc_id", vpce.VpcId) + d.Set("ip_address_type", vpce.IpAddressType) respPl, err := conn.DescribePrefixLists(&ec2.DescribePrefixListsInput{ Filters: BuildAttributeFilterList(map[string]string{ From 101da9c9e1242283020f01b221d36273b37585da Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 6 Jun 2022 13:53:40 +0300 Subject: [PATCH 02/16] docs + dns type --- internal/service/ec2/vpc_endpoint.go | 56 ++++++++++++++++++++++- website/docs/r/vpc_endpoint.html.markdown | 6 +++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/internal/service/ec2/vpc_endpoint.go b/internal/service/ec2/vpc_endpoint.go index 3576d3ef997c..9563633b1370 100644 --- a/internal/service/ec2/vpc_endpoint.go +++ b/internal/service/ec2/vpc_endpoint.go @@ -65,6 +65,20 @@ func ResourceVPCEndpoint() *schema.Resource { }, }, }, + "dns_options": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dns_record_ip_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(ec2.DnsRecordIpType_Values(), false), + }, + }, + }, + }, "ip_address_type": { Type: schema.TypeString, Optional: true, @@ -185,6 +199,10 @@ func resourceVPCEndpointCreate(d *schema.ResourceData, meta interface{}) error { req.IpAddressType = aws.String(v.(string)) } + if v, ok := d.GetOk("dns_options"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + req.DnsOptions = expandDNSOptions(v.([]interface{})[0].(map[string]interface{})) + } + setVPCEndpointCreateList(d, "route_table_ids", &req.RouteTableIds) setVPCEndpointCreateList(d, "subnet_ids", &req.SubnetIds) setVPCEndpointCreateList(d, "security_group_ids", &req.SecurityGroupIds) @@ -245,6 +263,10 @@ func resourceVPCEndpointRead(d *schema.ResourceData, meta interface{}) error { d.Set("vpc_id", vpce.VpcId) d.Set("ip_address_type", vpce.IpAddressType) + if err := d.Set("dns_options", []interface{}{flattenDNSOptions(vpce.DnsOptions)}); err != nil { + return fmt.Errorf("error setting dns_options: %w", err) + } + respPl, err := conn.DescribePrefixLists(&ec2.DescribePrefixListsInput{ Filters: BuildAttributeFilterList(map[string]string{ "prefix-list-name": serviceName, @@ -335,11 +357,15 @@ func resourceVPCEndpointUpdate(d *schema.ResourceData, meta interface{}) error { } } - if d.HasChanges("policy", "route_table_ids", "subnet_ids", "security_group_ids", "private_dns_enabled") { + if d.HasChanges("policy", "route_table_ids", "subnet_ids", "security_group_ids", "private_dns_enabled", "ip_address_type") { req := &ec2.ModifyVpcEndpointInput{ VpcEndpointId: aws.String(d.Id()), } + if d.HasChange("ip_address_type") { + req.IpAddressType = aws.String(d.Get("ip_address_type").(string)) + } + if d.HasChange("policy") { o, n := d.GetChange("policy") @@ -502,3 +528,31 @@ func flattenVPCEndpointSecurityGroupIds(groups []*ec2.SecurityGroupIdentifier) * return schema.NewSet(schema.HashString, vSecurityGroupIds) } + +func expandDNSOptions(tfMap map[string]interface{}) *ec2.DnsOptionsSpecification { + if tfMap == nil { + return nil + } + + config := &ec2.DnsOptionsSpecification{} + + if v, ok := tfMap["dns_record_ip_type"].(string); ok && v != "" { + config.DnsRecordIpType = aws.String(v) + } + + return config +} + +func flattenDNSOptions(apiObject *ec2.DnsOptions) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.DnsRecordIpType; v != nil { + tfMap["dns_record_ip_type"] = aws.StringValue(v) + } + + return tfMap +} diff --git a/website/docs/r/vpc_endpoint.html.markdown b/website/docs/r/vpc_endpoint.html.markdown index 39acd91043e2..a41602f5e7da 100644 --- a/website/docs/r/vpc_endpoint.html.markdown +++ b/website/docs/r/vpc_endpoint.html.markdown @@ -120,6 +120,8 @@ The following arguments are supported: * `policy` - (Optional) A policy to attach to the endpoint that controls access to the service. This is a JSON formatted string. Defaults to full access. All `Gateway` and some `Interface` endpoints support policies - see the [relevant AWS documentation](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-endpoints-access.html) for more details. For more information about building AWS IAM policy documents with Terraform, see the [AWS IAM Policy Document Guide](https://learn.hashicorp.com/terraform/aws/iam-policy). * `private_dns_enabled` - (Optional; AWS services and AWS Marketplace partner services only) Whether or not to associate a private hosted zone with the specified VPC. Applicable for endpoints of type `Interface`. Defaults to `false`. +* `dns_options` - (Optional) The DNS options for the endpoint. See dns_options below. +* `ip_address_type` - (Optional) The IP address type for the endpoint. Valid values are `ipv4`, `dualstack`, and `ipv6`. * `route_table_ids` - (Optional) One or more route table IDs. Applicable for endpoints of type `Gateway`. * `subnet_ids` - (Optional) The ID of one or more subnets in which to create a network interface for the endpoint. Applicable for endpoints of type `GatewayLoadBalancer` and `Interface`. * `security_group_ids` - (Optional) The ID of one or more security groups to associate with the network interface. Applicable for endpoints of type `Interface`. @@ -127,6 +129,10 @@ If no security groups are specified, the VPC's [default security group](https:// * `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. * `vpc_endpoint_type` - (Optional) The VPC endpoint type, `Gateway`, `GatewayLoadBalancer`, or `Interface`. Defaults to `Gateway`. +### dns_options + +* `dns_record_ip_type` - (Optional) The DNS records created for the endpoint. Valid values are `ipv4`, `dualstack`, `service-defined`, and `ipv6`. + ### Timeouts `aws_vpc_endpoint` provides the following From 7b08f07cdeacafba113a623d3e62e711f8a6903c Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 6 Jun 2022 14:11:30 +0300 Subject: [PATCH 03/16] supressdiff --- internal/service/ec2/vpc_endpoint.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/service/ec2/vpc_endpoint.go b/internal/service/ec2/vpc_endpoint.go index 9563633b1370..a3269f54c9d7 100644 --- a/internal/service/ec2/vpc_endpoint.go +++ b/internal/service/ec2/vpc_endpoint.go @@ -66,9 +66,10 @@ func ResourceVPCEndpoint() *schema.Resource { }, }, "dns_options": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, + Type: schema.TypeList, + Optional: true, + DiffSuppressFunc: verify.SuppressMissingOptionalConfigurationBlock, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "dns_record_ip_type": { From 4c04b6ded8f894fe8133db5148f941107ca0b3da Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 6 Jun 2022 15:12:55 +0300 Subject: [PATCH 04/16] computed --- internal/service/ec2/vpc_endpoint.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/service/ec2/vpc_endpoint.go b/internal/service/ec2/vpc_endpoint.go index a3269f54c9d7..72a9a44eff42 100644 --- a/internal/service/ec2/vpc_endpoint.go +++ b/internal/service/ec2/vpc_endpoint.go @@ -68,6 +68,7 @@ func ResourceVPCEndpoint() *schema.Resource { "dns_options": { Type: schema.TypeList, Optional: true, + Computed: true, DiffSuppressFunc: verify.SuppressMissingOptionalConfigurationBlock, MaxItems: 1, Elem: &schema.Resource{ @@ -83,6 +84,7 @@ func ResourceVPCEndpoint() *schema.Resource { "ip_address_type": { Type: schema.TypeString, Optional: true, + Computed: true, ValidateFunc: validation.StringInSlice(ec2.IpAddressType_Values(), false), }, "network_interface_ids": { From 945c8f5577d721719e4d24b216f59d942dda5068 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 6 Jun 2022 15:14:58 +0300 Subject: [PATCH 05/16] changelog --- .changelog/25190.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/25190.txt diff --git a/.changelog/25190.txt b/.changelog/25190.txt new file mode 100644 index 000000000000..a9f6802963c8 --- /dev/null +++ b/.changelog/25190.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_vpc_endpoint: Add `dns_options` and `ip_address_type` arguments +``` \ No newline at end of file From d221b5513a6be405b93b49cb6a680883521c3464 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 6 Jun 2022 15:34:11 +0300 Subject: [PATCH 06/16] test --- internal/service/ec2/vpc_endpoint_test.go | 54 +++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/internal/service/ec2/vpc_endpoint_test.go b/internal/service/ec2/vpc_endpoint_test.go index a0bbad942755..9bb85ee11432 100644 --- a/internal/service/ec2/vpc_endpoint_test.go +++ b/internal/service/ec2/vpc_endpoint_test.go @@ -245,6 +245,35 @@ func TestAccVPCEndpoint_interfaceBasic(t *testing.T) { }) } +func TestAccVPCEndpoint_ipType(t *testing.T) { + var endpoint ec2.VpcEndpoint + resourceName := "aws_vpc_endpoint.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckVPCEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccVPCEndpointConfig_ipType(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckVPCEndpointExists(resourceName, &endpoint), + resource.TestCheckResourceAttr(resourceName, "dns_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "dns_options.0.dns_record_ip_type", "ipv4"), + resource.TestCheckResourceAttr(resourceName, "ip_address_type", "ipv4"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccVPCEndpoint_interfaceWithSubnetAndSecurityGroup(t *testing.T) { var endpoint ec2.VpcEndpoint resourceName := "aws_vpc_endpoint.test" @@ -746,6 +775,31 @@ resource "aws_vpc_endpoint" "test" { `, rName) } +func testAccVPCEndpointConfig_ipType(rName string) string { + return fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + + tags = { + Name = %[1]q + } +} + +data "aws_region" "current" {} + +resource "aws_vpc_endpoint" "test" { + vpc_id = aws_vpc.test.id + service_name = "com.amazonaws.${data.aws_region.current.name}.ec2" + vpc_endpoint_type = "Interface" + ip_address_type = "ipv4" + + dns_options { + dns_record_ip_type = "ipv4" + } +} +`, rName) +} + func testAccVPCEndpointConfig_gatewayPolicy(rName, policy string) string { return fmt.Sprintf(` data "aws_vpc_endpoint_service" "test" { From 2c0e65e8ddb109002bd45506e9a84e2e4b497b9b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 21 Jun 2022 16:04:55 -0400 Subject: [PATCH 07/16] r/aws_vpc_endpoint_service: Use 'ServiceConnectivityType_Values()' (#14601). --- internal/service/ec2/vpc_endpoint_service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/ec2/vpc_endpoint_service.go b/internal/service/ec2/vpc_endpoint_service.go index 7f2fca6f5380..266ee7e6ed3d 100644 --- a/internal/service/ec2/vpc_endpoint_service.go +++ b/internal/service/ec2/vpc_endpoint_service.go @@ -123,7 +123,7 @@ func ResourceVPCEndpointService() *schema.Resource { Computed: true, Elem: &schema.Schema{ Type: schema.TypeString, - ValidateFunc: validation.StringInSlice([]string{"ipv4", "ipv6"}, false), + ValidateFunc: validation.StringInSlice(ec2.ServiceConnectivityType_Values(), false), }, }, "tags": tftags.TagsSchema(), From 81ae922387d6bbc43c333f4206951054aa8dbddd Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Jun 2022 08:47:08 -0400 Subject: [PATCH 08/16] Additional error code to skip. --- internal/service/ec2/ec2_instance_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/service/ec2/ec2_instance_test.go b/internal/service/ec2/ec2_instance_test.go index ba061c3d9d51..82612ba0982d 100644 --- a/internal/service/ec2/ec2_instance_test.go +++ b/internal/service/ec2/ec2_instance_test.go @@ -38,6 +38,7 @@ func testAccErrorCheckSkip(t *testing.T) resource.ErrorCheckFunc { "Unsupported volume type", "HostLimitExceeded", "ReservationCapacityExceeded", + "InsufficientInstanceCapacity", ) } From a01087994f98f7a4b6ea277bc8073d5870a34994 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Jun 2022 08:55:24 -0400 Subject: [PATCH 09/16] Add 'FindPrefixLists' and friends. --- internal/service/ec2/errors.go | 1 + internal/service/ec2/find.go | 59 ++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/internal/service/ec2/errors.go b/internal/service/ec2/errors.go index dc04318edfbc..6489b37ead32 100644 --- a/internal/service/ec2/errors.go +++ b/internal/service/ec2/errors.go @@ -57,6 +57,7 @@ const ( errCodeInvalidPlacementGroupUnknown = "InvalidPlacementGroup.Unknown" errCodeInvalidPoolIDNotFound = "InvalidPoolID.NotFound" errCodeInvalidPrefixListIDNotFound = "InvalidPrefixListID.NotFound" + errCodeInvalidPrefixListIdNotFound = "InvalidPrefixListId.NotFound" errCodeInvalidRouteNotFound = "InvalidRoute.NotFound" errCodeInvalidRouteTableIDNotFound = "InvalidRouteTableID.NotFound" errCodeInvalidRouteTableIdNotFound = "InvalidRouteTableId.NotFound" diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index 339fe690d83a..0790c62122b2 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -4705,6 +4705,65 @@ func FindPlacementGroupByName(conn *ec2.EC2, name string) (*ec2.PlacementGroup, return placementGroup, nil } +func FindPrefixList(conn *ec2.EC2, input *ec2.DescribePrefixListsInput) (*ec2.PrefixList, error) { + output, err := FindPrefixLists(conn, input) + + if err != nil { + return nil, err + } + + if len(output) == 0 || output[0] == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + if count := len(output); count > 1 { + return nil, tfresource.NewTooManyResultsError(count, input) + } + + return output[0], nil +} + +func FindPrefixLists(conn *ec2.EC2, input *ec2.DescribePrefixListsInput) ([]*ec2.PrefixList, error) { + var output []*ec2.PrefixList + + err := conn.DescribePrefixListsPages(input, func(page *ec2.DescribePrefixListsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, v := range page.PrefixLists { + if v != nil { + output = append(output, v) + } + } + + return !lastPage + }) + + if tfawserr.ErrCodeEquals(err, errCodeInvalidPrefixListIdNotFound) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + return output, nil +} + +func FindPrefixListByName(conn *ec2.EC2, name string) (*ec2.PrefixList, error) { + input := &ec2.DescribePrefixListsInput{ + Filters: BuildAttributeFilterList(map[string]string{ + "prefix-list-name": name, + }), + } + + return FindPrefixList(conn, input) +} + func FindVPCEndpointConnectionByServiceIDAndVPCEndpointID(conn *ec2.EC2, serviceID, vpcEndpointID string) (*ec2.VpcEndpointConnection, error) { input := &ec2.DescribeVpcEndpointConnectionsInput{ Filters: BuildAttributeFilterList(map[string]string{ From eecec3d76e7bf9b7e420a261f785d6c71d1dc0be Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Jun 2022 10:23:17 -0400 Subject: [PATCH 10/16] r/aws_vpc_endpoint: Tidy up resource Create and Delete. Acceptance test output: % make testacc TESTARGS='-run=TestAccVPCEndpoint_gatewayBasic' PKG=ec2 ACCTEST_PARALLELISM=2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 2 -run=TestAccVPCEndpoint_gatewayBasic -timeout 180m === RUN TestAccVPCEndpoint_gatewayBasic === PAUSE TestAccVPCEndpoint_gatewayBasic === CONT TestAccVPCEndpoint_gatewayBasic --- PASS: TestAccVPCEndpoint_gatewayBasic (30.72s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 34.762s --- internal/service/ec2/find.go | 10 ++ internal/service/ec2/vpc_endpoint.go | 133 ++++++++++------------ internal/service/ec2/vpc_endpoint_test.go | 114 +++++++------------ 3 files changed, 111 insertions(+), 146 deletions(-) diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index 0790c62122b2..a7ca496a082f 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -2651,6 +2651,16 @@ func FindVPCEndpointServiceConfigurations(conn *ec2.EC2, input *ec2.DescribeVpcE return output, nil } +func FindVPCEndpointServiceConfigurationByServiceName(conn *ec2.EC2, name string) (*ec2.ServiceConfiguration, error) { + input := &ec2.DescribeVpcEndpointServiceConfigurationsInput{ + Filters: BuildAttributeFilterList(map[string]string{ + "service-name": name, + }), + } + + return FindVPCEndpointServiceConfiguration(conn, input) +} + func FindVPCEndpointServices(conn *ec2.EC2, input *ec2.DescribeVpcEndpointServicesInput) ([]*ec2.ServiceDetail, []string, error) { var serviceDetails []*ec2.ServiceDetail var serviceNames []string diff --git a/internal/service/ec2/vpc_endpoint.go b/internal/service/ec2/vpc_endpoint.go index 72a9a44eff42..5ef1cd2b5f0c 100644 --- a/internal/service/ec2/vpc_endpoint.go +++ b/internal/service/ec2/vpc_endpoint.go @@ -31,6 +31,7 @@ func ResourceVPCEndpoint() *schema.Resource { Read: resourceVPCEndpointRead, Update: resourceVPCEndpointUpdate, Delete: resourceVPCEndpointDelete, + Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, @@ -91,7 +92,6 @@ func ResourceVPCEndpoint() *schema.Resource { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, "owner_id": { Type: schema.TypeString, @@ -126,14 +126,12 @@ func ResourceVPCEndpoint() *schema.Resource { Optional: true, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, "security_group_ids": { Type: schema.TypeSet, Optional: true, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, "service_name": { Type: schema.TypeString, @@ -149,7 +147,6 @@ func ResourceVPCEndpoint() *schema.Resource { Optional: true, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, "tags": tftags.TagsSchema(), "tags_all": tftags.TagsSchemaComputed(), @@ -182,41 +179,53 @@ func resourceVPCEndpointCreate(d *schema.ResourceData, meta interface{}) error { defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{}))) - req := &ec2.CreateVpcEndpointInput{ - VpcId: aws.String(d.Get("vpc_id").(string)), - VpcEndpointType: aws.String(d.Get("vpc_endpoint_type").(string)), - ServiceName: aws.String(d.Get("service_name").(string)), + serviceName := d.Get("service_name").(string) + input := &ec2.CreateVpcEndpointInput{ PrivateDnsEnabled: aws.Bool(d.Get("private_dns_enabled").(bool)), - TagSpecifications: tagSpecificationsFromKeyValueTags(tags, "vpc-endpoint"), + ServiceName: aws.String(serviceName), + TagSpecifications: tagSpecificationsFromKeyValueTags(tags, ec2.ResourceTypeVpcEndpoint), + VpcEndpointType: aws.String(d.Get("vpc_endpoint_type").(string)), + VpcId: aws.String(d.Get("vpc_id").(string)), + } + + if v, ok := d.GetOk("dns_options"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.DnsOptions = expandDNSOptionsSpecification(v.([]interface{})[0].(map[string]interface{})) + } + + if v, ok := d.GetOk("ip_address_type"); ok { + input.IpAddressType = aws.String(v.(string)) } if v, ok := d.GetOk("policy"); ok { policy, err := structure.NormalizeJsonString(v) + if err != nil { - return fmt.Errorf("policy contains an invalid JSON: %s", err) + return fmt.Errorf("policy contains invalid JSON: %w", err) } - req.PolicyDocument = aws.String(policy) + + input.PolicyDocument = aws.String(policy) } - if v, ok := d.GetOk("ip_address_type"); ok { - req.IpAddressType = aws.String(v.(string)) + if v, ok := d.GetOk("route_table_ids"); ok && v.(*schema.Set).Len() > 0 { + input.RouteTableIds = flex.ExpandStringSet(v.(*schema.Set)) } - if v, ok := d.GetOk("dns_options"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { - req.DnsOptions = expandDNSOptions(v.([]interface{})[0].(map[string]interface{})) + if v, ok := d.GetOk("security_group_ids"); ok && v.(*schema.Set).Len() > 0 { + input.SubnetIds = flex.ExpandStringSet(v.(*schema.Set)) + } + + if v, ok := d.GetOk("subnet_ids"); ok && v.(*schema.Set).Len() > 0 { + input.SubnetIds = flex.ExpandStringSet(v.(*schema.Set)) } - setVPCEndpointCreateList(d, "route_table_ids", &req.RouteTableIds) - setVPCEndpointCreateList(d, "subnet_ids", &req.SubnetIds) - setVPCEndpointCreateList(d, "security_group_ids", &req.SecurityGroupIds) + log.Printf("[DEBUG] Creating EC2 VPC Endpoint: %s", input) + output, err := conn.CreateVpcEndpoint(input) - log.Printf("[DEBUG] Creating VPC Endpoint: %#v", req) - resp, err := conn.CreateVpcEndpoint(req) if err != nil { - return fmt.Errorf("Error creating VPC Endpoint: %s", err) + return fmt.Errorf("creating EC2 VPC Endpoint (%s): %w", serviceName, err) } - vpce := resp.VpcEndpoint + vpce := output.VpcEndpoint d.SetId(aws.StringValue(vpce.VpcEndpointId)) if d.Get("auto_accept").(bool) && aws.StringValue(vpce.State) == vpcEndpointStatePendingAcceptance { @@ -225,10 +234,8 @@ func resourceVPCEndpointCreate(d *schema.ResourceData, meta interface{}) error { } } - _, err = WaitVPCEndpointAvailable(conn, d.Id(), d.Timeout(schema.TimeoutCreate)) - - if err != nil { - return fmt.Errorf("error waiting for VPC Endpoint (%s) to become available: %w", d.Id(), err) + if _, err = WaitVPCEndpointAvailable(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return fmt.Errorf("waiting for EC2 VPC Endpoint (%s) create: %w", d.Id(), err) } return resourceVPCEndpointRead(d, meta) @@ -266,8 +273,12 @@ func resourceVPCEndpointRead(d *schema.ResourceData, meta interface{}) error { d.Set("vpc_id", vpce.VpcId) d.Set("ip_address_type", vpce.IpAddressType) - if err := d.Set("dns_options", []interface{}{flattenDNSOptions(vpce.DnsOptions)}); err != nil { - return fmt.Errorf("error setting dns_options: %w", err) + if vpce.DnsOptions != nil { + if err := d.Set("dns_options", []interface{}{flattenDNSOptions(vpce.DnsOptions)}); err != nil { + return fmt.Errorf("setting dns_options: %w", err) + } + } else { + d.Set("dns_options", nil) } respPl, err := conn.DescribePrefixLists(&ec2.DescribePrefixListsInput{ @@ -419,11 +430,10 @@ func resourceVPCEndpointUpdate(d *schema.ResourceData, meta interface{}) error { func resourceVPCEndpointDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).EC2Conn - input := &ec2.DeleteVpcEndpointsInput{ + log.Printf("[DEBUG] Deleting EC2 VPC Endpoint: %s", d.Id()) + output, err := conn.DeleteVpcEndpoints(&ec2.DeleteVpcEndpointsInput{ VpcEndpointIds: aws.StringSlice([]string{d.Id()}), - } - - output, err := conn.DeleteVpcEndpoints(input) + }) if err == nil && output != nil { err = UnsuccessfulItemsError(output.Unsuccessful) @@ -434,63 +444,42 @@ func resourceVPCEndpointDelete(d *schema.ResourceData, meta interface{}) error { } if err != nil { - return fmt.Errorf("error deleting EC2 VPC Endpoint (%s): %w", d.Id(), err) + return fmt.Errorf("deleting EC2 VPC Endpoint (%s): %w", d.Id(), err) } - _, err = WaitVPCEndpointDeleted(conn, d.Id(), d.Timeout(schema.TimeoutDelete)) - - if err != nil { - return fmt.Errorf("error waiting for EC2 VPC Endpoint (%s) to delete: %w", d.Id(), err) + if _, err = WaitVPCEndpointDeleted(conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { + return fmt.Errorf("waiting for EC2 VPC Endpoint (%s) delete: %w", d.Id(), err) } return nil } -func vpcEndpointAccept(conn *ec2.EC2, vpceId, svcName string, timeout time.Duration) error { - describeSvcReq := &ec2.DescribeVpcEndpointServiceConfigurationsInput{} - describeSvcReq.Filters = BuildAttributeFilterList( - map[string]string{ - "service-name": svcName, - }, - ) +func vpcEndpointAccept(conn *ec2.EC2, vpceID, serviceName string, timeout time.Duration) error { + serviceConfiguration, err := FindVPCEndpointServiceConfigurationByServiceName(conn, serviceName) - describeSvcResp, err := conn.DescribeVpcEndpointServiceConfigurations(describeSvcReq) if err != nil { - return fmt.Errorf("error reading VPC Endpoint Service (%s): %s", svcName, err) - } - if describeSvcResp == nil || len(describeSvcResp.ServiceConfigurations) == 0 { - return fmt.Errorf("No matching VPC Endpoint Service found") + return fmt.Errorf("reading EC2 VPC Endpoint Service Configuration (%s): %w", serviceName, err) } - acceptEpReq := &ec2.AcceptVpcEndpointConnectionsInput{ - ServiceId: describeSvcResp.ServiceConfigurations[0].ServiceId, - VpcEndpointIds: aws.StringSlice([]string{vpceId}), + input := &ec2.AcceptVpcEndpointConnectionsInput{ + ServiceId: serviceConfiguration.ServiceId, + VpcEndpointIds: aws.StringSlice([]string{vpceID}), } - log.Printf("[DEBUG] Accepting VPC Endpoint connection: %#v", acceptEpReq) - _, err = conn.AcceptVpcEndpointConnections(acceptEpReq) + log.Printf("[DEBUG] Accepting EC2 VPC Endpoint connection: %s", input) + _, err = conn.AcceptVpcEndpointConnections(input) + if err != nil { - return fmt.Errorf("error accepting VPC Endpoint (%s) connection: %s", vpceId, err) + return fmt.Errorf("accepting EC2 VPC Endpoint (%s) connection: %w", vpceID, err) } - _, err = WaitVPCEndpointAccepted(conn, vpceId, timeout) - - if err != nil { - return fmt.Errorf("error waiting for VPC Endpoint (%s) to be accepted: %w", vpceId, err) + if _, err = WaitVPCEndpointAccepted(conn, vpceID, timeout); err != nil { + return fmt.Errorf("waiting for EC2 VPC Endpoint (%s) acceptance: %w", vpceID, err) } return nil } -func setVPCEndpointCreateList(d *schema.ResourceData, key string, c *[]*string) { - if v, ok := d.GetOk(key); ok { - list := v.(*schema.Set) - if list.Len() > 0 { - *c = flex.ExpandStringSet(list) - } - } -} - func setVPCEndpointUpdateLists(d *schema.ResourceData, key string, a, r *[]*string) { if d.HasChange(key) { o, n := d.GetChange(key) @@ -532,18 +521,18 @@ func flattenVPCEndpointSecurityGroupIds(groups []*ec2.SecurityGroupIdentifier) * return schema.NewSet(schema.HashString, vSecurityGroupIds) } -func expandDNSOptions(tfMap map[string]interface{}) *ec2.DnsOptionsSpecification { +func expandDNSOptionsSpecification(tfMap map[string]interface{}) *ec2.DnsOptionsSpecification { if tfMap == nil { return nil } - config := &ec2.DnsOptionsSpecification{} + apiObject := &ec2.DnsOptionsSpecification{} if v, ok := tfMap["dns_record_ip_type"].(string); ok && v != "" { - config.DnsRecordIpType = aws.String(v) + apiObject.DnsRecordIpType = aws.String(v) } - return config + return apiObject } func flattenDNSOptions(apiObject *ec2.DnsOptions) map[string]interface{} { diff --git a/internal/service/ec2/vpc_endpoint_test.go b/internal/service/ec2/vpc_endpoint_test.go index 9bb85ee11432..9def30dee8ae 100644 --- a/internal/service/ec2/vpc_endpoint_test.go +++ b/internal/service/ec2/vpc_endpoint_test.go @@ -3,8 +3,6 @@ package ec2_test import ( "fmt" "regexp" - "strconv" - "strings" "testing" "github.com/aws/aws-sdk-go/service/ec2" @@ -30,19 +28,24 @@ func TestAccVPCEndpoint_gatewayBasic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccVPCEndpointConfig_gatewayBasic(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckVPCEndpointExists(resourceName, &endpoint), - testAccCheckVPCEndpointPrefixListAvailable(resourceName), - resource.TestCheckResourceAttr(resourceName, "vpc_endpoint_type", "Gateway"), - resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "0"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), + acctest.CheckResourceAttrGreaterThanValue(resourceName, "cidr_blocks.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dns_entry.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dns_options.#", "0"), + resource.TestCheckResourceAttr(resourceName, "ip_address_type", ""), resource.TestCheckResourceAttr(resourceName, "network_interface_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "security_group_ids.#", "0"), + acctest.CheckResourceAttrAccountID(resourceName, "owner_id"), + resource.TestCheckResourceAttrSet(resourceName, "policy"), + resource.TestCheckResourceAttrSet(resourceName, "prefix_list_id"), resource.TestCheckResourceAttr(resourceName, "private_dns_enabled", "false"), resource.TestCheckResourceAttr(resourceName, "requester_managed", "false"), + resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "security_group_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - acctest.CheckResourceAttrAccountID(resourceName, "owner_id"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), + resource.TestCheckResourceAttr(resourceName, "vpc_endpoint_type", "Gateway"), ), }, { @@ -54,11 +57,32 @@ func TestAccVPCEndpoint_gatewayBasic(t *testing.T) { }) } +func TestAccVPCEndpoint_disappears(t *testing.T) { + var endpoint ec2.VpcEndpoint + resourceName := "aws_vpc_endpoint.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckVPCEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccVPCEndpointConfig_gatewayBasic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckVPCEndpointExists(resourceName, &endpoint), + acctest.CheckResourceDisappears(acctest.Provider, tfec2.ResourceVPCEndpoint(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func TestAccVPCEndpoint_gatewayWithRouteTableAndPolicy(t *testing.T) { var endpoint ec2.VpcEndpoint - var routeTable ec2.RouteTable resourceName := "aws_vpc_endpoint.test" - routeTableResourceName := "aws_route_table.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ @@ -71,8 +95,6 @@ func TestAccVPCEndpoint_gatewayWithRouteTableAndPolicy(t *testing.T) { Config: testAccVPCEndpointConfig_gatewayRouteTableAndPolicy(rName), Check: resource.ComposeTestCheckFunc( testAccCheckVPCEndpointExists(resourceName, &endpoint), - testAccCheckRouteTableExists(routeTableResourceName, &routeTable), - testAccCheckVPCEndpointPrefixListAvailable(resourceName), resource.TestCheckResourceAttr(resourceName, "vpc_endpoint_type", "Gateway"), resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "1"), resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "0"), @@ -90,8 +112,6 @@ func TestAccVPCEndpoint_gatewayWithRouteTableAndPolicy(t *testing.T) { Config: testAccVPCEndpointConfig_gatewayRouteTableAndPolicyModified(rName), Check: resource.ComposeTestCheckFunc( testAccCheckVPCEndpointExists(resourceName, &endpoint), - testAccCheckRouteTableExists(routeTableResourceName, &routeTable), - testAccCheckVPCEndpointPrefixListAvailable(resourceName), resource.TestCheckResourceAttr(resourceName, "vpc_endpoint_type", "Gateway"), resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "0"), @@ -434,29 +454,6 @@ func TestAccVPCEndpoint_interfaceNonAWSServiceAcceptOnUpdate(t *testing.T) { // }) } -func TestAccVPCEndpoint_disappears(t *testing.T) { - var endpoint ec2.VpcEndpoint - resourceName := "aws_vpc_endpoint.test" - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), - ProviderFactories: acctest.ProviderFactories, - CheckDestroy: testAccCheckVPCEndpointDestroy, - Steps: []resource.TestStep{ - { - Config: testAccVPCEndpointConfig_gatewayBasic(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckVPCEndpointExists(resourceName, &endpoint), - acctest.CheckResourceDisappears(acctest.Provider, tfec2.ResourceVPCEndpoint(), resourceName), - ), - ExpectNonEmptyPlan: true, - }, - }, - }) -} - func TestAccVPCEndpoint_tags(t *testing.T) { var endpoint ec2.VpcEndpoint resourceName := "aws_vpc_endpoint.test" @@ -552,7 +549,7 @@ func testAccCheckVPCEndpointDestroy(s *terraform.State) error { return nil } -func testAccCheckVPCEndpointExists(n string, endpoint *ec2.VpcEndpoint) resource.TestCheckFunc { +func testAccCheckVPCEndpointExists(n string, v *ec2.VpcEndpoint) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -560,49 +557,18 @@ func testAccCheckVPCEndpointExists(n string, endpoint *ec2.VpcEndpoint) resource } if rs.Primary.ID == "" { - return fmt.Errorf("No VPC Endpoint ID is set") + return fmt.Errorf("No EC2 VPC Endpoint ID is set") } conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Conn - out, err := tfec2.FindVPCEndpointByID(conn, rs.Primary.ID) + output, err := tfec2.FindVPCEndpointByID(conn, rs.Primary.ID) if err != nil { return err } - *endpoint = *out - - return nil - } -} - -func testAccCheckVPCEndpointPrefixListAvailable(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - prefixListID := rs.Primary.Attributes["prefix_list_id"] - if prefixListID == "" { - return fmt.Errorf("Prefix list ID not available") - } - if !strings.HasPrefix(prefixListID, "pl") { - return fmt.Errorf("Prefix list ID does not appear to be a valid value: '%s'", prefixListID) - } - - var ( - cidrBlockSize int - err error - ) - - if cidrBlockSize, err = strconv.Atoi(rs.Primary.Attributes["cidr_blocks.#"]); err != nil { - return err - } - if cidrBlockSize < 1 { - return fmt.Errorf("cidr_blocks seem suspiciously low: %d", cidrBlockSize) - } + *v = *output return nil } From 2aa6a76e93f713e45195838cff95bbaae584abf6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Jun 2022 11:10:51 -0400 Subject: [PATCH 11/16] d/aws_prefix_list: Tidy up. Acceptance test output: % make testacc TESTARGS='-run=TestAccVPCPrefixListDataSource_' PKG=ec2 ACCTEST_PARALLELISM=2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 2 -run=TestAccVPCPrefixListDataSource_ -timeout 180m === RUN TestAccVPCPrefixListDataSource_basic === PAUSE TestAccVPCPrefixListDataSource_basic === RUN TestAccVPCPrefixListDataSource_filter === PAUSE TestAccVPCPrefixListDataSource_filter === RUN TestAccVPCPrefixListDataSource_nameDoesNotOverrideFilter === PAUSE TestAccVPCPrefixListDataSource_nameDoesNotOverrideFilter === CONT TestAccVPCPrefixListDataSource_basic === CONT TestAccVPCPrefixListDataSource_nameDoesNotOverrideFilter === CONT TestAccVPCPrefixListDataSource_filter --- PASS: TestAccVPCPrefixListDataSource_nameDoesNotOverrideFilter (4.49s) --- PASS: TestAccVPCPrefixListDataSource_basic (18.75s) --- PASS: TestAccVPCPrefixListDataSource_filter (17.17s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 29.464s --- .../ec2/vpc_prefix_list_data_source.go | 57 ++++++------- .../ec2/vpc_prefix_list_data_source_test.go | 83 ++++--------------- 2 files changed, 40 insertions(+), 100 deletions(-) diff --git a/internal/service/ec2/vpc_prefix_list_data_source.go b/internal/service/ec2/vpc_prefix_list_data_source.go index c51198769a89..7becf31eb53e 100644 --- a/internal/service/ec2/vpc_prefix_list_data_source.go +++ b/internal/service/ec2/vpc_prefix_list_data_source.go @@ -1,13 +1,11 @@ package ec2 import ( - "fmt" - "log" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func DataSourcePrefixList() *schema.Resource { @@ -15,21 +13,21 @@ func DataSourcePrefixList() *schema.Resource { Read: dataSourcePrefixListRead, Schema: map[string]*schema.Schema{ - "prefix_list_id": { - Type: schema.TypeString, - Optional: true, + "cidr_blocks": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, }, + "filter": CustomFiltersSchema(), "name": { Type: schema.TypeString, Optional: true, Computed: true, }, - "cidr_blocks": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, + "prefix_list_id": { + Type: schema.TypeString, + Optional: true, }, - "filter": DataSourceFiltersSchema(), }, } } @@ -37,36 +35,31 @@ func DataSourcePrefixList() *schema.Resource { func dataSourcePrefixListRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).EC2Conn - filters, filtersOk := d.GetOk("filter") + input := &ec2.DescribePrefixListsInput{} - req := &ec2.DescribePrefixListsInput{} - if filtersOk { - req.Filters = BuildFiltersDataSource(filters.(*schema.Set)) + if v, ok := d.GetOk("name"); ok { + input.Filters = append(input.Filters, BuildAttributeFilterList(map[string]string{ + "prefix-list-name": v.(string), + })...) } - if prefixListID := d.Get("prefix_list_id"); prefixListID != "" { - req.PrefixListIds = aws.StringSlice([]string{prefixListID.(string)}) - } - if prefixListName := d.Get("name"); prefixListName.(string) != "" { - req.Filters = append(req.Filters, &ec2.Filter{ - Name: aws.String("prefix-list-name"), - Values: aws.StringSlice([]string{prefixListName.(string)}), - }) + + if v, ok := d.GetOk("prefix_list_id"); ok { + input.PrefixListIds = aws.StringSlice([]string{v.(string)}) } - log.Printf("[DEBUG] Reading Prefix List: %s", req) - resp, err := conn.DescribePrefixLists(req) + input.Filters = append(input.Filters, BuildCustomFilterList( + d.Get("filter").(*schema.Set), + )...) + + pl, err := FindPrefixList(conn, input) + if err != nil { - return err - } - if resp == nil || len(resp.PrefixLists) == 0 { - return fmt.Errorf("no matching prefix list found; the prefix list ID or name may be invalid or not exist in the current region") + return tfresource.SingularDataSourceFindError("EC2 Prefix List", err) } - pl := resp.PrefixLists[0] - d.SetId(aws.StringValue(pl.PrefixListId)) - d.Set("name", pl.PrefixListName) d.Set("cidr_blocks", aws.StringValueSlice(pl.Cidrs)) + d.Set("name", pl.PrefixListName) return nil } diff --git a/internal/service/ec2/vpc_prefix_list_data_source_test.go b/internal/service/ec2/vpc_prefix_list_data_source_test.go index c451642afeb9..32510ad23a6e 100644 --- a/internal/service/ec2/vpc_prefix_list_data_source_test.go +++ b/internal/service/ec2/vpc_prefix_list_data_source_test.go @@ -1,21 +1,18 @@ package ec2_test import ( - "fmt" "regexp" - "strconv" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" - "github.com/hashicorp/terraform-provider-aws/internal/conns" - tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" ) func TestAccVPCPrefixListDataSource_basic(t *testing.T) { + ds1Name := "data.aws_prefix_list.s3_by_id" + ds2Name := "data.aws_prefix_list.s3_by_name" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), @@ -24,8 +21,10 @@ func TestAccVPCPrefixListDataSource_basic(t *testing.T) { { Config: testAccVPCPrefixListDataSourceConfig_basic, Check: resource.ComposeTestCheckFunc( - testAccPrefixListCheckDataSource("data.aws_prefix_list.s3_by_id"), - testAccPrefixListCheckDataSource("data.aws_prefix_list.s3_by_name"), + acctest.CheckResourceAttrGreaterThanValue(ds1Name, "cidr_blocks.#", "0"), + resource.TestCheckResourceAttrSet(ds1Name, "name"), + acctest.CheckResourceAttrGreaterThanValue(ds2Name, "cidr_blocks.#", "0"), + resource.TestCheckResourceAttrSet(ds2Name, "name"), ), }, }, @@ -33,6 +32,9 @@ func TestAccVPCPrefixListDataSource_basic(t *testing.T) { } func TestAccVPCPrefixListDataSource_filter(t *testing.T) { + ds1Name := "data.aws_prefix_list.s3_by_id" + ds2Name := "data.aws_prefix_list.s3_by_name" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), @@ -41,8 +43,10 @@ func TestAccVPCPrefixListDataSource_filter(t *testing.T) { { Config: testAccVPCPrefixListDataSourceConfig_filter, Check: resource.ComposeTestCheckFunc( - testAccPrefixListCheckDataSource("data.aws_prefix_list.s3_by_id"), - testAccPrefixListCheckDataSource("data.aws_prefix_list.s3_by_name"), + acctest.CheckResourceAttrGreaterThanValue(ds1Name, "cidr_blocks.#", "0"), + resource.TestCheckResourceAttrSet(ds1Name, "name"), + acctest.CheckResourceAttrGreaterThanValue(ds2Name, "cidr_blocks.#", "0"), + resource.TestCheckResourceAttrSet(ds2Name, "name"), ), }, }, @@ -57,69 +61,12 @@ func TestAccVPCPrefixListDataSource_nameDoesNotOverrideFilter(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccVPCPrefixListDataSourceConfig_nameDoesNotOverrideFilter, - ExpectError: regexp.MustCompile(`no matching prefix list found`), + ExpectError: regexp.MustCompile(`no matching EC2 Prefix List found`), }, }, }) } -func testAccPrefixListCheckDataSource(name string) resource.TestCheckFunc { - getPrefixListId := func(name string) (string, error) { - conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Conn - - input := ec2.DescribePrefixListsInput{ - Filters: tfec2.BuildAttributeFilterList(map[string]string{ - "prefix-list-name": name, - }), - } - - output, err := conn.DescribePrefixLists(&input) - if err != nil { - return "", err - } - - if len(output.PrefixLists) != 1 { - return "", fmt.Errorf("prefix list %s not found", name) - } - - return aws.StringValue(output.PrefixLists[0].PrefixListId), nil - } - - 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) - } - - attr := rs.Primary.Attributes - - region := acctest.Region() - prefixListName := fmt.Sprintf("com.amazonaws.%s.s3", region) - prefixListId, err := getPrefixListId(prefixListName) - if err != nil { - return err - } - - if attr["name"] != prefixListName { - return fmt.Errorf("bad name %s", attr["name"]) - } - if attr["id"] != prefixListId { - return fmt.Errorf("bad id %s", attr["id"]) - } - - var cidrBlockSize int - - if cidrBlockSize, err = strconv.Atoi(attr["cidr_blocks.#"]); err != nil { - return err - } - if cidrBlockSize < 1 { - return fmt.Errorf("cidr_blocks seem suspiciously low: %d", cidrBlockSize) - } - - return nil - } -} - const testAccVPCPrefixListDataSourceConfig_basic = ` data "aws_region" "current" {} From d9b2521298137f1099b955e306b82f95edf97a25 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Jun 2022 12:27:56 -0400 Subject: [PATCH 12/16] r/aws_vpc_endpoint: Tidy up resource Read. Acceptance test output: % make testacc TESTARGS='-run=TestAccVPCEndpoint_gatewayBasic\|TestAccVPCEndpoint_interfaceBasic\|TestAccVPCEndpoint_disappears' PKG=ec2 ACCTEST_PARALLELISM=2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 2 -run=TestAccVPCEndpoint_gatewayBasic\|TestAccVPCEndpoint_interfaceBasic\|TestAccVPCEndpoint_disappears -timeout 180m === RUN TestAccVPCEndpoint_gatewayBasic === PAUSE TestAccVPCEndpoint_gatewayBasic === RUN TestAccVPCEndpoint_interfaceBasic === PAUSE TestAccVPCEndpoint_interfaceBasic === RUN TestAccVPCEndpoint_disappears === PAUSE TestAccVPCEndpoint_disappears === CONT TestAccVPCEndpoint_gatewayBasic === CONT TestAccVPCEndpoint_disappears --- PASS: TestAccVPCEndpoint_disappears (34.96s) === CONT TestAccVPCEndpoint_interfaceBasic --- PASS: TestAccVPCEndpoint_gatewayBasic (39.17s) --- PASS: TestAccVPCEndpoint_interfaceBasic (70.19s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 115.148s --- internal/service/ec2/vpc_endpoint.go | 156 ++++++++-------- .../service/ec2/vpc_endpoint_data_source.go | 136 ++++++-------- internal/service/ec2/vpc_endpoint_test.go | 171 +++++++++--------- 3 files changed, 219 insertions(+), 244 deletions(-) diff --git a/internal/service/ec2/vpc_endpoint.go b/internal/service/ec2/vpc_endpoint.go index 5ef1cd2b5f0c..ca807bf9b3c4 100644 --- a/internal/service/ec2/vpc_endpoint.go +++ b/internal/service/ec2/vpc_endpoint.go @@ -265,14 +265,12 @@ func resourceVPCEndpointRead(d *schema.ResourceData, meta interface{}) error { AccountID: aws.StringValue(vpce.OwnerId), Resource: fmt.Sprintf("vpc-endpoint/%s", d.Id()), }.String() - d.Set("arn", arn) - serviceName := aws.StringValue(vpce.ServiceName) - d.Set("service_name", serviceName) - d.Set("state", vpce.State) - d.Set("vpc_id", vpce.VpcId) - d.Set("ip_address_type", vpce.IpAddressType) + d.Set("arn", arn) + if err := d.Set("dns_entry", flattenDNSEntries(vpce.DnsEntries)); err != nil { + return fmt.Errorf("setting dns_entry: %w", err) + } if vpce.DnsOptions != nil { if err := d.Set("dns_options", []interface{}{flattenDNSOptions(vpce.DnsOptions)}); err != nil { return fmt.Errorf("setting dns_options: %w", err) @@ -280,38 +278,34 @@ func resourceVPCEndpointRead(d *schema.ResourceData, meta interface{}) error { } else { d.Set("dns_options", nil) } - - respPl, err := conn.DescribePrefixLists(&ec2.DescribePrefixListsInput{ - Filters: BuildAttributeFilterList(map[string]string{ - "prefix-list-name": serviceName, - }), - }) - if err != nil { - return fmt.Errorf("error reading Prefix List (%s): %s", serviceName, err) - } - if respPl == nil || len(respPl.PrefixLists) == 0 { - d.Set("cidr_blocks", []interface{}{}) - } else if len(respPl.PrefixLists) > 1 { - return fmt.Errorf("multiple prefix lists associated with the service name '%s'. Unexpected", serviceName) + d.Set("ip_address_type", vpce.IpAddressType) + d.Set("network_interface_ids", aws.StringValueSlice(vpce.NetworkInterfaceIds)) + d.Set("owner_id", vpce.OwnerId) + d.Set("private_dns_enabled", vpce.PrivateDnsEnabled) + d.Set("requester_managed", vpce.RequesterManaged) + d.Set("route_table_ids", aws.StringValueSlice(vpce.RouteTableIds)) + d.Set("security_group_ids", flattenSecurityGroupIdentifiers(vpce.Groups)) + d.Set("service_name", serviceName) + d.Set("state", vpce.State) + d.Set("subnet_ids", aws.StringValueSlice(vpce.SubnetIds)) + // VPC endpoints don't have types in GovCloud, so set type to default if empty + if v := aws.StringValue(vpce.VpcEndpointType); v == "" { + d.Set("vpc_endpoint_type", ec2.VpcEndpointTypeGateway) } else { - pl := respPl.PrefixLists[0] - - d.Set("prefix_list_id", pl.PrefixListId) - err = d.Set("cidr_blocks", flex.FlattenStringList(pl.Cidrs)) - if err != nil { - return fmt.Errorf("error setting cidr_blocks: %s", err) - } + d.Set("vpc_endpoint_type", v) } + d.Set("vpc_id", vpce.VpcId) - err = d.Set("dns_entry", flattenVPCEndpointDNSEntries(vpce.DnsEntries)) - if err != nil { - return fmt.Errorf("error setting dns_entry: %s", err) - } - err = d.Set("network_interface_ids", flex.FlattenStringSet(vpce.NetworkInterfaceIds)) - if err != nil { - return fmt.Errorf("error setting network_interface_ids: %s", err) + if pl, err := FindPrefixListByName(conn, serviceName); err != nil { + if tfresource.NotFound(err) { + d.Set("cidr_blocks", nil) + } else { + return fmt.Errorf("reading EC2 Prefix List (%s): %w", serviceName, err) + } + } else { + d.Set("cidr_blocks", aws.StringValueSlice(pl.Cidrs)) + d.Set("prefix_list_id", pl.PrefixListId) } - d.Set("owner_id", vpce.OwnerId) policyToSet, err := verify.SecondJSONUnlessEquivalent(d.Get("policy").(string), aws.StringValue(vpce.PolicyDocument)) @@ -327,36 +321,15 @@ func resourceVPCEndpointRead(d *schema.ResourceData, meta interface{}) error { d.Set("policy", policyToSet) - d.Set("private_dns_enabled", vpce.PrivateDnsEnabled) - err = d.Set("route_table_ids", flex.FlattenStringSet(vpce.RouteTableIds)) - if err != nil { - return fmt.Errorf("error setting route_table_ids: %s", err) - } - d.Set("requester_managed", vpce.RequesterManaged) - err = d.Set("security_group_ids", flattenVPCEndpointSecurityGroupIds(vpce.Groups)) - if err != nil { - return fmt.Errorf("error setting security_group_ids: %s", err) - } - err = d.Set("subnet_ids", flex.FlattenStringSet(vpce.SubnetIds)) - if err != nil { - return fmt.Errorf("error setting subnet_ids: %s", err) - } - // VPC endpoints don't have types in GovCloud, so set type to default if empty - if vpceType := aws.StringValue(vpce.VpcEndpointType); vpceType == "" { - d.Set("vpc_endpoint_type", ec2.VpcEndpointTypeGateway) - } else { - d.Set("vpc_endpoint_type", vpceType) - } - tags := KeyValueTags(vpce.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig) //lintignore:AWSR002 if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { - return fmt.Errorf("error setting tags: %w", err) + return fmt.Errorf("setting tags: %w", err) } if err := d.Set("tags_all", tags.Map()); err != nil { - return fmt.Errorf("error setting tags_all: %w", err) + return fmt.Errorf("setting tags_all: %w", err) } return nil @@ -498,41 +471,54 @@ func setVPCEndpointUpdateLists(d *schema.ResourceData, key string, a, r *[]*stri } } -func flattenVPCEndpointDNSEntries(dnsEntries []*ec2.DnsEntry) []interface{} { - vDnsEntries := []interface{}{} +func expandDNSOptionsSpecification(tfMap map[string]interface{}) *ec2.DnsOptionsSpecification { + if tfMap == nil { + return nil + } + + apiObject := &ec2.DnsOptionsSpecification{} - for _, dnsEntry := range dnsEntries { - vDnsEntries = append(vDnsEntries, map[string]interface{}{ - "dns_name": aws.StringValue(dnsEntry.DnsName), - "hosted_zone_id": aws.StringValue(dnsEntry.HostedZoneId), - }) + if v, ok := tfMap["dns_record_ip_type"].(string); ok && v != "" { + apiObject.DnsRecordIpType = aws.String(v) } - return vDnsEntries + return apiObject } -func flattenVPCEndpointSecurityGroupIds(groups []*ec2.SecurityGroupIdentifier) *schema.Set { - vSecurityGroupIds := []interface{}{} +func flattenDNSEntry(apiObject *ec2.DnsEntry) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.DnsName; v != nil { + tfMap["dns_name"] = aws.StringValue(v) + } - for _, group := range groups { - vSecurityGroupIds = append(vSecurityGroupIds, aws.StringValue(group.GroupId)) + if v := apiObject.HostedZoneId; v != nil { + tfMap["hosted_zone_id"] = aws.StringValue(v) } - return schema.NewSet(schema.HashString, vSecurityGroupIds) + return tfMap } -func expandDNSOptionsSpecification(tfMap map[string]interface{}) *ec2.DnsOptionsSpecification { - if tfMap == nil { +func flattenDNSEntries(apiObjects []*ec2.DnsEntry) []interface{} { + if len(apiObjects) == 0 { return nil } - apiObject := &ec2.DnsOptionsSpecification{} + var tfList []interface{} - if v, ok := tfMap["dns_record_ip_type"].(string); ok && v != "" { - apiObject.DnsRecordIpType = aws.String(v) + for _, apiObject := range apiObjects { + if apiObject == nil { + continue + } + + tfList = append(tfList, flattenDNSEntry(apiObject)) } - return apiObject + return tfList } func flattenDNSOptions(apiObject *ec2.DnsOptions) map[string]interface{} { @@ -548,3 +534,21 @@ func flattenDNSOptions(apiObject *ec2.DnsOptions) map[string]interface{} { return tfMap } + +func flattenSecurityGroupIdentifiers(apiObjects []*ec2.SecurityGroupIdentifier) []string { + if len(apiObjects) == 0 { + return nil + } + + var tfList []string + + for _, apiObject := range apiObjects { + if apiObject == nil { + continue + } + + tfList = append(tfList, aws.StringValue(apiObject.GroupId)) + } + + return tfList +} diff --git a/internal/service/ec2/vpc_endpoint_data_source.go b/internal/service/ec2/vpc_endpoint_data_source.go index 1c1ab2b61c83..afa823d0d00d 100644 --- a/internal/service/ec2/vpc_endpoint_data_source.go +++ b/internal/service/ec2/vpc_endpoint_data_source.go @@ -2,7 +2,6 @@ package ec2 import ( "fmt" - "log" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" @@ -10,8 +9,8 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" "github.com/hashicorp/terraform-provider-aws/internal/conns" - "github.com/hashicorp/terraform-provider-aws/internal/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func DataSourceVPCEndpoint() *schema.Resource { @@ -54,7 +53,6 @@ func DataSourceVPCEndpoint() *schema.Resource { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, "owner_id": { Type: schema.TypeString, @@ -80,13 +78,11 @@ func DataSourceVPCEndpoint() *schema.Resource { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, "security_group_ids": { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, "service_name": { Type: schema.TypeString, @@ -102,7 +98,6 @@ func DataSourceVPCEndpoint() *schema.Resource { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, "tags": tftags.TagsSchemaComputed(), "vpc_endpoint_type": { @@ -122,45 +117,37 @@ func dataSourceVPCEndpointRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).EC2Conn ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - req := &ec2.DescribeVpcEndpointsInput{} + input := &ec2.DescribeVpcEndpointsInput{ + Filters: BuildAttributeFilterList( + 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 id, ok := d.GetOk("id"); ok { - req.VpcEndpointIds = aws.StringSlice([]string{id.(string)}) + if v, ok := d.GetOk("id"); ok { + input.VpcEndpointIds = aws.StringSlice([]string{v.(string)}) } - req.Filters = BuildAttributeFilterList( - map[string]string{ - "vpc-endpoint-state": d.Get("state").(string), - "vpc-id": d.Get("vpc_id").(string), - "service-name": d.Get("service_name").(string), - }, - ) - req.Filters = append(req.Filters, BuildTagFilterList( + input.Filters = append(input.Filters, BuildTagFilterList( Tags(tftags.New(d.Get("tags").(map[string]interface{}))), )...) - req.Filters = append(req.Filters, BuildCustomFilterList( + input.Filters = append(input.Filters, BuildCustomFilterList( d.Get("filter").(*schema.Set), )...) - if len(req.Filters) == 0 { + if len(input.Filters) == 0 { // Don't send an empty filters list; the EC2 API won't accept it. - req.Filters = nil + input.Filters = nil } - log.Printf("[DEBUG] Reading VPC Endpoint: %s", req) - respVpce, err := conn.DescribeVpcEndpoints(req) + vpce, err := FindVPCEndpoint(conn, input) + if err != nil { - return fmt.Errorf("error reading VPC Endpoint: %w", err) - } - if respVpce == nil || len(respVpce.VpcEndpoints) == 0 { - return fmt.Errorf("no matching VPC Endpoint found") - } - if len(respVpce.VpcEndpoints) > 1 { - return fmt.Errorf("multiple VPC Endpoints matched; use additional constraints to reduce matches to a single VPC Endpoint") + return tfresource.SingularDataSourceFindError("EC2 VPC Endpoint", err) } - vpce := respVpce.VpcEndpoints[0] - d.SetId(aws.StringValue(vpce.VpcEndpointId)) - arn := arn.ARN{ Partition: meta.(*conns.AWSClient).Partition, Service: ec2.ServiceName, @@ -168,72 +155,51 @@ func dataSourceVPCEndpointRead(d *schema.ResourceData, meta interface{}) error { AccountID: aws.StringValue(vpce.OwnerId), Resource: fmt.Sprintf("vpc-endpoint/%s", d.Id()), }.String() - d.Set("arn", arn) - serviceName := aws.StringValue(vpce.ServiceName) + + d.SetId(aws.StringValue(vpce.VpcEndpointId)) + d.Set("arn", arn) + if err := d.Set("dns_entry", flattenDNSEntries(vpce.DnsEntries)); err != nil { + return fmt.Errorf("setting dns_entry: %w", err) + } + d.Set("network_interface_ids", aws.StringValueSlice(vpce.NetworkInterfaceIds)) + d.Set("owner_id", vpce.OwnerId) + d.Set("private_dns_enabled", vpce.PrivateDnsEnabled) + d.Set("requester_managed", vpce.RequesterManaged) + d.Set("route_table_ids", aws.StringValueSlice(vpce.RouteTableIds)) + d.Set("security_group_ids", flattenSecurityGroupIdentifiers(vpce.Groups)) d.Set("service_name", serviceName) d.Set("state", vpce.State) + d.Set("subnet_ids", aws.StringValueSlice(vpce.SubnetIds)) + // VPC endpoints don't have types in GovCloud, so set type to default if empty + if v := aws.StringValue(vpce.VpcEndpointType); v == "" { + d.Set("vpc_endpoint_type", ec2.VpcEndpointTypeGateway) + } else { + d.Set("vpc_endpoint_type", v) + } d.Set("vpc_id", vpce.VpcId) - respPl, err := conn.DescribePrefixLists(&ec2.DescribePrefixListsInput{ - Filters: BuildAttributeFilterList(map[string]string{ - "prefix-list-name": serviceName, - }), - }) - if err != nil { - return fmt.Errorf("error reading Prefix List (%s): %w", serviceName, err) - } - if respPl == nil || len(respPl.PrefixLists) == 0 { - d.Set("cidr_blocks", []interface{}{}) - } else if len(respPl.PrefixLists) > 1 { - return fmt.Errorf("multiple prefix lists associated with the service name '%s'. Unexpected", serviceName) + if pl, err := FindPrefixListByName(conn, serviceName); err != nil { + if tfresource.NotFound(err) { + d.Set("cidr_blocks", nil) + } else { + return fmt.Errorf("reading EC2 Prefix List (%s): %w", serviceName, err) + } } else { - pl := respPl.PrefixLists[0] - + d.Set("cidr_blocks", aws.StringValueSlice(pl.Cidrs)) d.Set("prefix_list_id", pl.PrefixListId) - err = d.Set("cidr_blocks", flex.FlattenStringList(pl.Cidrs)) - if err != nil { - return fmt.Errorf("error setting cidr_blocks: %w", err) - } } - err = d.Set("dns_entry", flattenVPCEndpointDNSEntries(vpce.DnsEntries)) - if err != nil { - return fmt.Errorf("error setting dns_entry: %w", err) - } - err = d.Set("network_interface_ids", flex.FlattenStringSet(vpce.NetworkInterfaceIds)) - if err != nil { - return fmt.Errorf("error setting network_interface_ids: %w", err) - } - d.Set("owner_id", vpce.OwnerId) policy, err := structure.NormalizeJsonString(aws.StringValue(vpce.PolicyDocument)) + if err != nil { - return fmt.Errorf("policy contains an invalid JSON: %w", err) + return fmt.Errorf("policy contains invalid JSON: %w", err) } + d.Set("policy", policy) - d.Set("private_dns_enabled", vpce.PrivateDnsEnabled) - err = d.Set("route_table_ids", flex.FlattenStringSet(vpce.RouteTableIds)) - if err != nil { - return fmt.Errorf("error setting route_table_ids: %w", err) - } - d.Set("requester_managed", vpce.RequesterManaged) - err = d.Set("security_group_ids", flattenVPCEndpointSecurityGroupIds(vpce.Groups)) - if err != nil { - return fmt.Errorf("error setting security_group_ids: %w", err) - } - err = d.Set("subnet_ids", flex.FlattenStringSet(vpce.SubnetIds)) - if err != nil { - return fmt.Errorf("error setting subnet_ids: %w", err) - } - err = d.Set("tags", KeyValueTags(vpce.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()) - if err != nil { - return fmt.Errorf("error setting tags: %w", err) - } - // VPC endpoints don't have types in GovCloud, so set type to default if empty - if vpceType := aws.StringValue(vpce.VpcEndpointType); vpceType == "" { - d.Set("vpc_endpoint_type", ec2.VpcEndpointTypeGateway) - } else { - d.Set("vpc_endpoint_type", vpceType) + + if err := d.Set("tags", KeyValueTags(vpce.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("setting tags: %w", err) } return nil diff --git a/internal/service/ec2/vpc_endpoint_test.go b/internal/service/ec2/vpc_endpoint_test.go index 9def30dee8ae..00ea39e9fe22 100644 --- a/internal/service/ec2/vpc_endpoint_test.go +++ b/internal/service/ec2/vpc_endpoint_test.go @@ -57,6 +57,49 @@ func TestAccVPCEndpoint_gatewayBasic(t *testing.T) { }) } +func TestAccVPCEndpoint_interfaceBasic(t *testing.T) { + var endpoint ec2.VpcEndpoint + resourceName := "aws_vpc_endpoint.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckVPCEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccVPCEndpointConfig_interfaceBasic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckVPCEndpointExists(resourceName, &endpoint), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), + resource.TestCheckResourceAttr(resourceName, "cidr_blocks.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dns_entry.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dns_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "dns_options.0.dns_record_ip_type", "ipv4"), + resource.TestCheckResourceAttr(resourceName, "ip_address_type", "ipv4"), + resource.TestCheckResourceAttr(resourceName, "network_interface_ids.#", "0"), + acctest.CheckResourceAttrAccountID(resourceName, "owner_id"), + resource.TestCheckResourceAttrSet(resourceName, "policy"), + resource.TestCheckNoResourceAttr(resourceName, "prefix_list_id"), + resource.TestCheckResourceAttr(resourceName, "private_dns_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "requester_managed", "false"), + resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "security_group_ids.#", "1"), // Default SG. + resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "vpc_endpoint_type", "Interface"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccVPCEndpoint_disappears(t *testing.T) { var endpoint ec2.VpcEndpoint resourceName := "aws_vpc_endpoint.test" @@ -80,6 +123,51 @@ func TestAccVPCEndpoint_disappears(t *testing.T) { }) } +func TestAccVPCEndpoint_tags(t *testing.T) { + var endpoint ec2.VpcEndpoint + resourceName := "aws_vpc_endpoint.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckVPCEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccVPCEndpointConfig_tags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckVPCEndpointExists(resourceName, &endpoint), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccVPCEndpointConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckVPCEndpointExists(resourceName, &endpoint), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccVPCEndpointConfig_tags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckVPCEndpointExists(resourceName, &endpoint), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + func TestAccVPCEndpoint_gatewayWithRouteTableAndPolicy(t *testing.T) { var endpoint ec2.VpcEndpoint resourceName := "aws_vpc_endpoint.test" @@ -227,44 +315,6 @@ func TestAccVPCEndpoint_ignoreEquivalent(t *testing.T) { }) } -func TestAccVPCEndpoint_interfaceBasic(t *testing.T) { - var endpoint ec2.VpcEndpoint - resourceName := "aws_vpc_endpoint.test" - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), - ProviderFactories: acctest.ProviderFactories, - CheckDestroy: testAccCheckVPCEndpointDestroy, - Steps: []resource.TestStep{ - { - Config: testAccVPCEndpointConfig_interfaceBasic(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckVPCEndpointExists(resourceName, &endpoint), - resource.TestCheckNoResourceAttr(resourceName, "prefix_list_id"), - resource.TestCheckResourceAttr(resourceName, "cidr_blocks.#", "0"), - resource.TestCheckResourceAttr(resourceName, "vpc_endpoint_type", "Interface"), - resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "network_interface_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "security_group_ids.#", "1"), - resource.TestCheckResourceAttr(resourceName, "private_dns_enabled", "false"), - resource.TestCheckResourceAttr(resourceName, "requester_managed", "false"), - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - acctest.CheckResourceAttrAccountID(resourceName, "owner_id"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - func TestAccVPCEndpoint_ipType(t *testing.T) { var endpoint ec2.VpcEndpoint resourceName := "aws_vpc_endpoint.test" @@ -454,51 +504,6 @@ func TestAccVPCEndpoint_interfaceNonAWSServiceAcceptOnUpdate(t *testing.T) { // }) } -func TestAccVPCEndpoint_tags(t *testing.T) { - var endpoint ec2.VpcEndpoint - resourceName := "aws_vpc_endpoint.test" - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), - ProviderFactories: acctest.ProviderFactories, - CheckDestroy: testAccCheckVPCEndpointDestroy, - Steps: []resource.TestStep{ - { - Config: testAccVPCEndpointConfig_tags1(rName, "key1", "value1"), - Check: resource.ComposeTestCheckFunc( - testAccCheckVPCEndpointExists(resourceName, &endpoint), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccVPCEndpointConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), - Check: resource.ComposeTestCheckFunc( - testAccCheckVPCEndpointExists(resourceName, &endpoint), - resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), - ), - }, - { - Config: testAccVPCEndpointConfig_tags1(rName, "key2", "value2"), - Check: resource.ComposeTestCheckFunc( - testAccCheckVPCEndpointExists(resourceName, &endpoint), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), - ), - }, - }, - }) -} - func TestAccVPCEndpoint_VPCEndpointType_gatewayLoadBalancer(t *testing.T) { var endpoint ec2.VpcEndpoint vpcEndpointServiceResourceName := "aws_vpc_endpoint_service.test" From 90008025109c9778289601971bc344eb48e04920 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Jun 2022 14:48:02 -0400 Subject: [PATCH 13/16] r/aws_vpc_endpoint: Tidy up resource Update. Acceptance test output: % make testacc TESTARGS='-run=TestAccVPCEndpoint_ipAddressType' PKG=ec2 ACCTEST_PARALLELISM=2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 2 -run=TestAccVPCEndpoint_ipAddressType -timeout 180m === RUN TestAccVPCEndpoint_ipAddressType === PAUSE TestAccVPCEndpoint_ipAddressType === CONT TestAccVPCEndpoint_ipAddressType --- PASS: TestAccVPCEndpoint_ipAddressType (330.17s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 334.085s --- internal/service/ec2/vpc_endpoint.go | 90 +++++++------ internal/service/ec2/vpc_endpoint_service.go | 35 +---- internal/service/ec2/vpc_endpoint_test.go | 133 +++++-------------- 3 files changed, 89 insertions(+), 169 deletions(-) diff --git a/internal/service/ec2/vpc_endpoint.go b/internal/service/ec2/vpc_endpoint.go index ca807bf9b3c4..169dac55d68f 100644 --- a/internal/service/ec2/vpc_endpoint.go +++ b/internal/service/ec2/vpc_endpoint.go @@ -344,56 +344,64 @@ func resourceVPCEndpointUpdate(d *schema.ResourceData, meta interface{}) error { } } - if d.HasChanges("policy", "route_table_ids", "subnet_ids", "security_group_ids", "private_dns_enabled", "ip_address_type") { - req := &ec2.ModifyVpcEndpointInput{ + if d.HasChanges("dns_options", "ip_address_type", "policy", "private_dns_enabled", "security_group_ids", "route_table_ids", "subnet_ids") { + input := &ec2.ModifyVpcEndpointInput{ VpcEndpointId: aws.String(d.Id()), } + if d.HasChange("dns_options") { + if v, ok := d.GetOk("dns_options"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.DnsOptions = expandDNSOptionsSpecification(v.([]interface{})[0].(map[string]interface{})) + } + } + if d.HasChange("ip_address_type") { - req.IpAddressType = aws.String(d.Get("ip_address_type").(string)) + input.IpAddressType = aws.String(d.Get("ip_address_type").(string)) + } + + if d.HasChange("private_dns_enabled") { + input.PrivateDnsEnabled = aws.Bool(d.Get("private_dns_enabled").(bool)) } + input.AddRouteTableIds, input.RemoveRouteTableIds = flattenAddAndRemoveStringLists(d, "route_table_ids") + input.AddSecurityGroupIds, input.RemoveSecurityGroupIds = flattenAddAndRemoveStringLists(d, "security_group_ids") + input.AddSubnetIds, input.RemoveSubnetIds = flattenAddAndRemoveStringLists(d, "subnet_ids") + if d.HasChange("policy") { o, n := d.GetChange("policy") if equivalent, err := awspolicy.PoliciesAreEquivalent(o.(string), n.(string)); err != nil || !equivalent { policy, err := structure.NormalizeJsonString(d.Get("policy")) + if err != nil { - return fmt.Errorf("policy contains an invalid JSON: %s", err) + return fmt.Errorf("policy contains invalid JSON: %w", err) } if policy == "" { - req.ResetPolicy = aws.Bool(true) + input.ResetPolicy = aws.Bool(true) } else { - req.PolicyDocument = aws.String(policy) + input.PolicyDocument = aws.String(policy) } } } - setVPCEndpointUpdateLists(d, "route_table_ids", &req.AddRouteTableIds, &req.RemoveRouteTableIds) - setVPCEndpointUpdateLists(d, "subnet_ids", &req.AddSubnetIds, &req.RemoveSubnetIds) - setVPCEndpointUpdateLists(d, "security_group_ids", &req.AddSecurityGroupIds, &req.RemoveSecurityGroupIds) + log.Printf("[DEBUG] Updating EC2 VPC Endpoint: %s", input) + _, err := conn.ModifyVpcEndpoint(input) - if d.HasChange("private_dns_enabled") { - req.PrivateDnsEnabled = aws.Bool(d.Get("private_dns_enabled").(bool)) - } - - log.Printf("[DEBUG] Updating VPC Endpoint: %#v", req) - if _, err := conn.ModifyVpcEndpoint(req); err != nil { - return fmt.Errorf("Error updating VPC Endpoint: %s", err) + if err != nil { + return fmt.Errorf("updating EC2 VPC Endpoint (%s): %w", d.Id(), err) } - _, err := WaitVPCEndpointAvailable(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)) - - if err != nil { - return fmt.Errorf("error waiting for VPC Endpoint (%s) to become available: %w", d.Id(), err) + if _, err := WaitVPCEndpointAvailable(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { + return fmt.Errorf("waiting for EC2 VPC Endpoint (%s) update: %w", d.Id(), err) } } if d.HasChange("tags_all") { o, n := d.GetChange("tags_all") + if err := UpdateTags(conn, d.Id(), o, n); err != nil { - return fmt.Errorf("error updating tags: %s", err) + return fmt.Errorf("updating tags: %w", err) } } @@ -453,24 +461,6 @@ func vpcEndpointAccept(conn *ec2.EC2, vpceID, serviceName string, timeout time.D return nil } -func setVPCEndpointUpdateLists(d *schema.ResourceData, key string, a, r *[]*string) { - if d.HasChange(key) { - o, n := d.GetChange(key) - os := o.(*schema.Set) - ns := n.(*schema.Set) - - add := flex.ExpandStringSet(ns.Difference(os)) - if len(add) > 0 { - *a = add - } - - remove := flex.ExpandStringSet(os.Difference(ns)) - if len(remove) > 0 { - *r = remove - } - } -} - func expandDNSOptionsSpecification(tfMap map[string]interface{}) *ec2.DnsOptionsSpecification { if tfMap == nil { return nil @@ -552,3 +542,25 @@ func flattenSecurityGroupIdentifiers(apiObjects []*ec2.SecurityGroupIdentifier) return tfList } + +func flattenAddAndRemoveStringLists(d *schema.ResourceData, key string) ([]*string, []*string) { + if !d.HasChange(key) { + return nil, nil + } + + var add, del []*string + + o, n := d.GetChange(key) + os := o.(*schema.Set) + ns := n.(*schema.Set) + + if v := flex.ExpandStringSet(ns.Difference(os)); len(v) > 0 { + add = v + } + + if v := flex.ExpandStringSet(os.Difference(ns)); len(v) > 0 { + del = v + } + + return add, del +} diff --git a/internal/service/ec2/vpc_endpoint_service.go b/internal/service/ec2/vpc_endpoint_service.go index 266ee7e6ed3d..1c987bb4ff33 100644 --- a/internal/service/ec2/vpc_endpoint_service.go +++ b/internal/service/ec2/vpc_endpoint_service.go @@ -276,24 +276,14 @@ func resourceVPCEndpointServiceUpdate(d *schema.ResourceData, meta interface{}) input.AcceptanceRequired = aws.Bool(d.Get("acceptance_required").(bool)) } - if d.HasChange("gateway_load_balancer_arns") { - setVPCEndpointServiceUpdateLists(d, "gateway_load_balancer_arns", - &input.AddGatewayLoadBalancerArns, &input.RemoveGatewayLoadBalancerArns) - } - - if d.HasChange("network_load_balancer_arns") { - setVPCEndpointServiceUpdateLists(d, "network_load_balancer_arns", - &input.AddNetworkLoadBalancerArns, &input.RemoveNetworkLoadBalancerArns) - } + input.AddGatewayLoadBalancerArns, input.RemoveGatewayLoadBalancerArns = flattenAddAndRemoveStringLists(d, "gateway_load_balancer_arns") + input.AddNetworkLoadBalancerArns, input.RemoveNetworkLoadBalancerArns = flattenAddAndRemoveStringLists(d, "network_load_balancer_arns") if d.HasChange("private_dns_name") { input.PrivateDnsName = aws.String(d.Get("private_dns_name").(string)) } - if d.HasChange("supported_ip_address_types") { - setVPCEndpointServiceUpdateLists(d, "supported_ip_address_types", - &input.AddSupportedIpAddressTypes, &input.RemoveSupportedIpAddressTypes) - } + input.AddSupportedIpAddressTypes, input.RemoveSupportedIpAddressTypes = flattenAddAndRemoveStringLists(d, "supported_ip_address_types") log.Printf("[DEBUG] Updating EC2 VPC Endpoint Service: %s", input) _, err := conn.ModifyVpcEndpointServiceConfiguration(input) @@ -312,8 +302,7 @@ func resourceVPCEndpointServiceUpdate(d *schema.ResourceData, meta interface{}) ServiceId: aws.String(d.Id()), } - setVPCEndpointServiceUpdateLists(d, "allowed_principals", - &input.AddAllowedPrincipals, &input.RemoveAllowedPrincipals) + input.AddAllowedPrincipals, input.RemoveAllowedPrincipals = flattenAddAndRemoveStringLists(d, "allowed_principals") if _, err := conn.ModifyVpcEndpointServicePermissions(input); err != nil { return fmt.Errorf("modifying EC2 VPC Endpoint Service (%s) permissions: %w", d.Id(), err) @@ -358,22 +347,6 @@ func resourceVPCEndpointServiceDelete(d *schema.ResourceData, meta interface{}) return nil } -func setVPCEndpointServiceUpdateLists(d *schema.ResourceData, key string, a, r *[]*string) { - o, n := d.GetChange(key) - os := o.(*schema.Set) - ns := n.(*schema.Set) - - add := flex.ExpandStringSet(ns.Difference(os)) - if len(add) > 0 { - *a = add - } - - remove := flex.ExpandStringSet(os.Difference(ns)) - if len(remove) > 0 { - *r = remove - } -} - func flattenAllowedPrincipal(apiObject *ec2.AllowedPrincipal) *string { if apiObject == nil { return nil diff --git a/internal/service/ec2/vpc_endpoint_test.go b/internal/service/ec2/vpc_endpoint_test.go index 00ea39e9fe22..7940149a14da 100644 --- a/internal/service/ec2/vpc_endpoint_test.go +++ b/internal/service/ec2/vpc_endpoint_test.go @@ -183,34 +183,16 @@ func TestAccVPCEndpoint_gatewayWithRouteTableAndPolicy(t *testing.T) { Config: testAccVPCEndpointConfig_gatewayRouteTableAndPolicy(rName), Check: resource.ComposeTestCheckFunc( testAccCheckVPCEndpointExists(resourceName, &endpoint), - resource.TestCheckResourceAttr(resourceName, "vpc_endpoint_type", "Gateway"), + resource.TestCheckResourceAttrSet(resourceName, "policy"), resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "1"), - resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "network_interface_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "security_group_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "private_dns_enabled", "false"), - resource.TestCheckResourceAttr(resourceName, "requester_managed", "false"), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), - acctest.CheckResourceAttrAccountID(resourceName, "owner_id"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), ), }, { Config: testAccVPCEndpointConfig_gatewayRouteTableAndPolicyModified(rName), Check: resource.ComposeTestCheckFunc( testAccCheckVPCEndpointExists(resourceName, &endpoint), - resource.TestCheckResourceAttr(resourceName, "vpc_endpoint_type", "Gateway"), - resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "network_interface_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "security_group_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "private_dns_enabled", "false"), - resource.TestCheckResourceAttr(resourceName, "requester_managed", "false"), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), - acctest.CheckResourceAttrAccountID(resourceName, "owner_id"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), + resource.TestCheckResourceAttr(resourceName, "policy", ""), + resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "1"), ), }, { @@ -315,7 +297,7 @@ func TestAccVPCEndpoint_ignoreEquivalent(t *testing.T) { }) } -func TestAccVPCEndpoint_ipType(t *testing.T) { +func TestAccVPCEndpoint_ipAddressType(t *testing.T) { var endpoint ec2.VpcEndpoint resourceName := "aws_vpc_endpoint.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -327,7 +309,7 @@ func TestAccVPCEndpoint_ipType(t *testing.T) { CheckDestroy: testAccCheckVPCEndpointDestroy, Steps: []resource.TestStep{ { - Config: testAccVPCEndpointConfig_ipType(rName), + Config: testAccVPCEndpointConfig_ipAddressType(rName, "ipv4"), Check: resource.ComposeTestCheckFunc( testAccCheckVPCEndpointExists(resourceName, &endpoint), resource.TestCheckResourceAttr(resourceName, "dns_options.#", "1"), @@ -336,9 +318,19 @@ func TestAccVPCEndpoint_ipType(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"auto_accept"}, + }, + { + Config: testAccVPCEndpointConfig_ipAddressType(rName, "dualstack"), + Check: resource.ComposeTestCheckFunc( + testAccCheckVPCEndpointExists(resourceName, &endpoint), + resource.TestCheckResourceAttr(resourceName, "dns_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "dns_options.0.dns_record_ip_type", "dualstack"), + resource.TestCheckResourceAttr(resourceName, "ip_address_type", "dualstack"), + ), }, }, }) @@ -359,38 +351,18 @@ func TestAccVPCEndpoint_interfaceWithSubnetAndSecurityGroup(t *testing.T) { Config: testAccVPCEndpointConfig_interfaceSubnet(rName), Check: resource.ComposeTestCheckFunc( testAccCheckVPCEndpointExists(resourceName, &endpoint), - resource.TestCheckNoResourceAttr(resourceName, "prefix_list_id"), - resource.TestCheckResourceAttr(resourceName, "cidr_blocks.#", "0"), - resource.TestCheckResourceAttr(resourceName, "vpc_endpoint_type", "Interface"), - resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "1"), resource.TestCheckResourceAttr(resourceName, "network_interface_ids.#", "1"), resource.TestCheckResourceAttr(resourceName, "security_group_ids.#", "2"), - resource.TestCheckResourceAttr(resourceName, "private_dns_enabled", "false"), - resource.TestCheckResourceAttr(resourceName, "requester_managed", "false"), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), - acctest.CheckResourceAttrAccountID(resourceName, "owner_id"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), + resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "1"), ), }, { Config: testAccVPCEndpointConfig_interfaceSubnetModified(rName), Check: resource.ComposeTestCheckFunc( testAccCheckVPCEndpointExists(resourceName, &endpoint), - resource.TestCheckNoResourceAttr(resourceName, "prefix_list_id"), - resource.TestCheckResourceAttr(resourceName, "cidr_blocks.#", "0"), - resource.TestCheckResourceAttr(resourceName, "vpc_endpoint_type", "Interface"), - resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "3"), resource.TestCheckResourceAttr(resourceName, "network_interface_ids.#", "1"), resource.TestCheckResourceAttr(resourceName, "security_group_ids.#", "1"), - resource.TestCheckResourceAttr(resourceName, "private_dns_enabled", "true"), - resource.TestCheckResourceAttr(resourceName, "requester_managed", "false"), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), - acctest.CheckResourceAttrAccountID(resourceName, "owner_id"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), + resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "3"), ), }, { @@ -417,20 +389,7 @@ func TestAccVPCEndpoint_interfaceNonAWSServiceAcceptOnCreate(t *testing.T) { // Config: testAccVPCEndpointConfig_interfaceNonAWSService(rName, true), Check: resource.ComposeTestCheckFunc( testAccCheckVPCEndpointExists(resourceName, &endpoint), - resource.TestCheckNoResourceAttr(resourceName, "prefix_list_id"), - resource.TestCheckResourceAttr(resourceName, "cidr_blocks.#", "0"), - resource.TestCheckResourceAttr(resourceName, "vpc_endpoint_type", "Interface"), - resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "network_interface_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "security_group_ids.#", "1"), - resource.TestCheckResourceAttr(resourceName, "private_dns_enabled", "false"), - resource.TestCheckResourceAttr(resourceName, "requester_managed", "false"), resource.TestCheckResourceAttr(resourceName, "state", "available"), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), - acctest.CheckResourceAttrAccountID(resourceName, "owner_id"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), ), }, { @@ -458,40 +417,14 @@ func TestAccVPCEndpoint_interfaceNonAWSServiceAcceptOnUpdate(t *testing.T) { // Config: testAccVPCEndpointConfig_interfaceNonAWSService(rName, false), Check: resource.ComposeTestCheckFunc( testAccCheckVPCEndpointExists(resourceName, &endpoint), - resource.TestCheckNoResourceAttr(resourceName, "prefix_list_id"), - resource.TestCheckResourceAttr(resourceName, "cidr_blocks.#", "0"), - resource.TestCheckResourceAttr(resourceName, "vpc_endpoint_type", "Interface"), - resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "network_interface_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "security_group_ids.#", "1"), - resource.TestCheckResourceAttr(resourceName, "private_dns_enabled", "false"), - resource.TestCheckResourceAttr(resourceName, "requester_managed", "false"), resource.TestCheckResourceAttr(resourceName, "state", "pendingAcceptance"), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), - acctest.CheckResourceAttrAccountID(resourceName, "owner_id"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), ), }, { Config: testAccVPCEndpointConfig_interfaceNonAWSService(rName, true), Check: resource.ComposeTestCheckFunc( testAccCheckVPCEndpointExists(resourceName, &endpoint), - resource.TestCheckNoResourceAttr(resourceName, "prefix_list_id"), - resource.TestCheckResourceAttr(resourceName, "cidr_blocks.#", "0"), - resource.TestCheckResourceAttr(resourceName, "vpc_endpoint_type", "Interface"), - resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "network_interface_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "security_group_ids.#", "1"), - resource.TestCheckResourceAttr(resourceName, "private_dns_enabled", "false"), - resource.TestCheckResourceAttr(resourceName, "requester_managed", "false"), resource.TestCheckResourceAttr(resourceName, "state", "available"), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), - acctest.CheckResourceAttrAccountID(resourceName, "owner_id"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), ), }, { @@ -746,29 +679,31 @@ resource "aws_vpc_endpoint" "test" { `, rName) } -func testAccVPCEndpointConfig_ipType(rName string) string { - return fmt.Sprintf(` -resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" +func testAccVPCEndpointConfig_ipAddressType(rName, addressType string) string { + return acctest.ConfigCompose(testAccVPCEndpointServiceConfig_supportedIPAddressTypesBase(rName), fmt.Sprintf(` +resource "aws_vpc_endpoint_service" "test" { + acceptance_required = false + network_load_balancer_arns = aws_lb.test[*].arn + supported_ip_address_types = ["ipv4", "ipv6"] tags = { Name = %[1]q } } -data "aws_region" "current" {} - resource "aws_vpc_endpoint" "test" { - vpc_id = aws_vpc.test.id - service_name = "com.amazonaws.${data.aws_region.current.name}.ec2" - vpc_endpoint_type = "Interface" - ip_address_type = "ipv4" + vpc_id = aws_vpc.test.id + service_name = aws_vpc_endpoint_service.test.service_name + vpc_endpoint_type = "Interface" + private_dns_enabled = false + auto_accept = true + ip_address_type = %[2]q dns_options { - dns_record_ip_type = "ipv4" + dns_record_ip_type = %[2]q } } -`, rName) +`, rName, addressType)) } func testAccVPCEndpointConfig_gatewayPolicy(rName, policy string) string { From 1d8753ce8239cf67cfd55b3387c6c737610819a3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Jun 2022 15:52:50 -0400 Subject: [PATCH 14/16] Fix typos. --- internal/service/ec2/vpc_endpoint.go | 2 +- internal/service/ec2/vpc_endpoint_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/ec2/vpc_endpoint.go b/internal/service/ec2/vpc_endpoint.go index 169dac55d68f..4a7f3dd7af2d 100644 --- a/internal/service/ec2/vpc_endpoint.go +++ b/internal/service/ec2/vpc_endpoint.go @@ -211,7 +211,7 @@ func resourceVPCEndpointCreate(d *schema.ResourceData, meta interface{}) error { } if v, ok := d.GetOk("security_group_ids"); ok && v.(*schema.Set).Len() > 0 { - input.SubnetIds = flex.ExpandStringSet(v.(*schema.Set)) + input.SecurityGroupIds = flex.ExpandStringSet(v.(*schema.Set)) } if v, ok := d.GetOk("subnet_ids"); ok && v.(*schema.Set).Len() > 0 { diff --git a/internal/service/ec2/vpc_endpoint_test.go b/internal/service/ec2/vpc_endpoint_test.go index 7940149a14da..7d193fc21b66 100644 --- a/internal/service/ec2/vpc_endpoint_test.go +++ b/internal/service/ec2/vpc_endpoint_test.go @@ -191,8 +191,8 @@ func TestAccVPCEndpoint_gatewayWithRouteTableAndPolicy(t *testing.T) { Config: testAccVPCEndpointConfig_gatewayRouteTableAndPolicyModified(rName), Check: resource.ComposeTestCheckFunc( testAccCheckVPCEndpointExists(resourceName, &endpoint), - resource.TestCheckResourceAttr(resourceName, "policy", ""), - resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "policy"), + resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "0"), ), }, { From 38b41411918cfcd36d720cca762d17871a7a5bb3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Jun 2022 16:07:25 -0400 Subject: [PATCH 15/16] Use 'aws_iam_session_context' for AllowedPrincipal. --- internal/service/ec2/vpc_endpoint_test.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/service/ec2/vpc_endpoint_test.go b/internal/service/ec2/vpc_endpoint_test.go index 7d193fc21b66..abd3cc5c21be 100644 --- a/internal/service/ec2/vpc_endpoint_test.go +++ b/internal/service/ec2/vpc_endpoint_test.go @@ -925,11 +925,13 @@ resource "aws_vpc_endpoint" "test" { } func testAccVPCEndpointConfig_gatewayLoadBalancer(rName string) string { - return acctest.ConfigCompose( - acctest.ConfigAvailableAZsNoOptIn(), - fmt.Sprintf(` + return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` data "aws_caller_identity" "current" {} +data "aws_iam_session_context" "current" { + arn = data.aws_caller_identity.current.arn +} + resource "aws_vpc" "test" { cidr_block = "10.10.10.0/25" @@ -963,7 +965,7 @@ resource "aws_lb" "test" { resource "aws_vpc_endpoint_service" "test" { acceptance_required = false - allowed_principals = [data.aws_caller_identity.current.arn] + allowed_principals = [data.aws_iam_session_context.current.issuer_arn] gateway_load_balancer_arns = [aws_lb.test.arn] tags = { From b516ead7545debc7a5682e89a9c943b2ee56fe00 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Jun 2022 16:40:27 -0400 Subject: [PATCH 16/16] d/aws_vpc_endpoint: Add 'dns_options' and 'ip_address_type' attributes Acceptance test output: % make testacc TESTARGS='-run=TestAccVPCEndpointDataSource_' PKG=ec2 ACCTEST_PARALLELISM=2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 2 -run=TestAccVPCEndpointDataSource_ -timeout 180m === RUN TestAccVPCEndpointDataSource_gatewayBasic === PAUSE TestAccVPCEndpointDataSource_gatewayBasic === RUN TestAccVPCEndpointDataSource_byID === PAUSE TestAccVPCEndpointDataSource_byID === RUN TestAccVPCEndpointDataSource_byFilter === PAUSE TestAccVPCEndpointDataSource_byFilter === RUN TestAccVPCEndpointDataSource_byTags === PAUSE TestAccVPCEndpointDataSource_byTags === RUN TestAccVPCEndpointDataSource_gatewayWithRouteTableAndTags === PAUSE TestAccVPCEndpointDataSource_gatewayWithRouteTableAndTags === RUN TestAccVPCEndpointDataSource_interface === PAUSE TestAccVPCEndpointDataSource_interface === CONT TestAccVPCEndpointDataSource_gatewayBasic === CONT TestAccVPCEndpointDataSource_byTags --- PASS: TestAccVPCEndpointDataSource_byTags (31.39s) === CONT TestAccVPCEndpointDataSource_interface --- PASS: TestAccVPCEndpointDataSource_gatewayBasic (31.66s) === CONT TestAccVPCEndpointDataSource_gatewayWithRouteTableAndTags --- PASS: TestAccVPCEndpointDataSource_gatewayWithRouteTableAndTags (31.21s) === CONT TestAccVPCEndpointDataSource_byFilter --- PASS: TestAccVPCEndpointDataSource_byFilter (29.74s) === CONT TestAccVPCEndpointDataSource_byID --- PASS: TestAccVPCEndpointDataSource_byID (67.13s) --- PASS: TestAccVPCEndpointDataSource_interface (137.23s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/ec2 172.994s --- .changelog/25190.txt | 4 + .../service/ec2/vpc_endpoint_data_source.go | 27 +- .../ec2/vpc_endpoint_data_source_test.go | 240 +++++++++++------- 3 files changed, 178 insertions(+), 93 deletions(-) diff --git a/.changelog/25190.txt b/.changelog/25190.txt index a9f6802963c8..f24fb3554b80 100644 --- a/.changelog/25190.txt +++ b/.changelog/25190.txt @@ -1,3 +1,7 @@ ```release-note:enhancement resource/aws_vpc_endpoint: Add `dns_options` and `ip_address_type` arguments +``` + +```release-note:enhancement +data-source/aws_vpc_endpoint: Add `dns_options` and `ip_address_type` attributes ``` \ No newline at end of file diff --git a/internal/service/ec2/vpc_endpoint_data_source.go b/internal/service/ec2/vpc_endpoint_data_source.go index afa823d0d00d..7f60ca0528dc 100644 --- a/internal/service/ec2/vpc_endpoint_data_source.go +++ b/internal/service/ec2/vpc_endpoint_data_source.go @@ -43,12 +43,28 @@ func DataSourceVPCEndpoint() *schema.Resource { }, }, }, + "dns_options": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dns_record_ip_type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, "filter": CustomFiltersSchema(), "id": { Type: schema.TypeString, Optional: true, Computed: true, }, + "ip_address_type": { + Type: schema.TypeString, + Computed: true, + }, "network_interface_ids": { Type: schema.TypeSet, Computed: true, @@ -148,6 +164,8 @@ func dataSourceVPCEndpointRead(d *schema.ResourceData, meta interface{}) error { return tfresource.SingularDataSourceFindError("EC2 VPC Endpoint", err) } + d.SetId(aws.StringValue(vpce.VpcEndpointId)) + arn := arn.ARN{ Partition: meta.(*conns.AWSClient).Partition, Service: ec2.ServiceName, @@ -157,11 +175,18 @@ func dataSourceVPCEndpointRead(d *schema.ResourceData, meta interface{}) error { }.String() serviceName := aws.StringValue(vpce.ServiceName) - d.SetId(aws.StringValue(vpce.VpcEndpointId)) d.Set("arn", arn) if err := d.Set("dns_entry", flattenDNSEntries(vpce.DnsEntries)); err != nil { return fmt.Errorf("setting dns_entry: %w", err) } + if vpce.DnsOptions != nil { + if err := d.Set("dns_options", []interface{}{flattenDNSOptions(vpce.DnsOptions)}); err != nil { + return fmt.Errorf("setting dns_options: %w", err) + } + } else { + d.Set("dns_options", nil) + } + d.Set("ip_address_type", vpce.IpAddressType) d.Set("network_interface_ids", aws.StringValueSlice(vpce.NetworkInterfaceIds)) d.Set("owner_id", vpce.OwnerId) d.Set("private_dns_enabled", vpce.PrivateDnsEnabled) diff --git a/internal/service/ec2/vpc_endpoint_data_source_test.go b/internal/service/ec2/vpc_endpoint_data_source_test.go index a4dabc27d128..9d002a1ddacf 100644 --- a/internal/service/ec2/vpc_endpoint_data_source_test.go +++ b/internal/service/ec2/vpc_endpoint_data_source_test.go @@ -2,7 +2,6 @@ package ec2_test import ( "fmt" - "regexp" "testing" "github.com/aws/aws-sdk-go/service/ec2" @@ -12,6 +11,7 @@ import ( ) func TestAccVPCEndpointDataSource_gatewayBasic(t *testing.T) { + resourceName := "aws_vpc_endpoint.test" datasourceName := "data.aws_vpc_endpoint.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -22,19 +22,27 @@ func TestAccVPCEndpointDataSource_gatewayBasic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccVPCEndpointDataSourceConfig_gatewayBasic(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(datasourceName, "vpc_endpoint_type", "Gateway"), - resource.TestCheckResourceAttrSet(datasourceName, "prefix_list_id"), - resource.TestCheckResourceAttrSet(datasourceName, "cidr_blocks.#"), - resource.TestCheckResourceAttr(datasourceName, "route_table_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "subnet_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "network_interface_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "security_group_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "private_dns_enabled", "false"), - resource.TestCheckResourceAttr(datasourceName, "requester_managed", "false"), - resource.TestCheckResourceAttr(datasourceName, "tags.%", "0"), - acctest.CheckResourceAttrAccountID(datasourceName, "owner_id"), - acctest.MatchResourceAttrRegionalARN(datasourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(datasourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(datasourceName, "cidr_blocks.#", resourceName, "cidr_blocks.#"), + resource.TestCheckResourceAttrPair(datasourceName, "dns_entry.#", resourceName, "dns_entry.#"), + resource.TestCheckResourceAttrPair(datasourceName, "dns_options.#", resourceName, "dns_options.#"), + resource.TestCheckResourceAttrPair(datasourceName, "id", resourceName, "id"), + resource.TestCheckResourceAttrPair(datasourceName, "ip_address_type", resourceName, "ip_address_type"), + resource.TestCheckResourceAttrPair(datasourceName, "network_interface_ids.#", resourceName, "network_interface_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "owner_id", resourceName, "owner_id"), + resource.TestCheckResourceAttrPair(datasourceName, "policy", resourceName, "policy"), + resource.TestCheckResourceAttrPair(datasourceName, "prefix_list_id", resourceName, "prefix_list_id"), + resource.TestCheckResourceAttrPair(datasourceName, "private_dns_enabled", resourceName, "private_dns_enabled"), + resource.TestCheckResourceAttrPair(datasourceName, "requester_managed", resourceName, "requester_managed"), + resource.TestCheckResourceAttrPair(datasourceName, "route_table_ids.#", resourceName, "route_table_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "security_group_ids.#", resourceName, "security_group_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "service_name", resourceName, "service_name"), + resource.TestCheckResourceAttrPair(datasourceName, "state", resourceName, "state"), + resource.TestCheckResourceAttrPair(datasourceName, "subnet_ids.#", resourceName, "subnet_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "tags.%", resourceName, "tags.%"), + resource.TestCheckResourceAttrPair(datasourceName, "vpc_endpoint_type", resourceName, "vpc_endpoint_type"), + resource.TestCheckResourceAttrPair(datasourceName, "vpc_id", resourceName, "vpc_id"), ), }, }, @@ -42,6 +50,7 @@ func TestAccVPCEndpointDataSource_gatewayBasic(t *testing.T) { } func TestAccVPCEndpointDataSource_byID(t *testing.T) { + resourceName := "aws_vpc_endpoint.test" datasourceName := "data.aws_vpc_endpoint.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -52,19 +61,27 @@ func TestAccVPCEndpointDataSource_byID(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccVPCEndpointDataSourceConfig_byID(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(datasourceName, "vpc_endpoint_type", "Gateway"), - resource.TestCheckResourceAttrSet(datasourceName, "prefix_list_id"), - resource.TestCheckResourceAttrSet(datasourceName, "cidr_blocks.#"), - resource.TestCheckResourceAttr(datasourceName, "route_table_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "subnet_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "network_interface_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "security_group_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "private_dns_enabled", "false"), - resource.TestCheckResourceAttr(datasourceName, "requester_managed", "false"), - resource.TestCheckResourceAttr(datasourceName, "tags.%", "0"), - acctest.CheckResourceAttrAccountID(datasourceName, "owner_id"), - acctest.MatchResourceAttrRegionalARN(datasourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(datasourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(datasourceName, "cidr_blocks.#", resourceName, "cidr_blocks.#"), + resource.TestCheckResourceAttrPair(datasourceName, "dns_entry.#", resourceName, "dns_entry.#"), + resource.TestCheckResourceAttrPair(datasourceName, "dns_options.#", resourceName, "dns_options.#"), + resource.TestCheckResourceAttrPair(datasourceName, "id", resourceName, "id"), + resource.TestCheckResourceAttrPair(datasourceName, "ip_address_type", resourceName, "ip_address_type"), + resource.TestCheckResourceAttrPair(datasourceName, "network_interface_ids.#", resourceName, "network_interface_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "owner_id", resourceName, "owner_id"), + resource.TestCheckResourceAttrPair(datasourceName, "policy", resourceName, "policy"), + resource.TestCheckResourceAttrPair(datasourceName, "prefix_list_id", resourceName, "prefix_list_id"), + resource.TestCheckResourceAttrPair(datasourceName, "private_dns_enabled", resourceName, "private_dns_enabled"), + resource.TestCheckResourceAttrPair(datasourceName, "requester_managed", resourceName, "requester_managed"), + resource.TestCheckResourceAttrPair(datasourceName, "route_table_ids.#", resourceName, "route_table_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "security_group_ids.#", resourceName, "security_group_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "service_name", resourceName, "service_name"), + resource.TestCheckResourceAttrPair(datasourceName, "state", resourceName, "state"), + resource.TestCheckResourceAttrPair(datasourceName, "subnet_ids.#", resourceName, "subnet_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "tags.%", resourceName, "tags.%"), + resource.TestCheckResourceAttrPair(datasourceName, "vpc_endpoint_type", resourceName, "vpc_endpoint_type"), + resource.TestCheckResourceAttrPair(datasourceName, "vpc_id", resourceName, "vpc_id"), ), }, }, @@ -72,6 +89,7 @@ func TestAccVPCEndpointDataSource_byID(t *testing.T) { } func TestAccVPCEndpointDataSource_byFilter(t *testing.T) { + resourceName := "aws_vpc_endpoint.test" datasourceName := "data.aws_vpc_endpoint.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -82,19 +100,27 @@ func TestAccVPCEndpointDataSource_byFilter(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccVPCEndpointDataSourceConfig_byFilter(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(datasourceName, "vpc_endpoint_type", "Gateway"), - resource.TestCheckResourceAttrSet(datasourceName, "prefix_list_id"), - resource.TestCheckResourceAttrSet(datasourceName, "cidr_blocks.#"), - resource.TestCheckResourceAttr(datasourceName, "route_table_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "subnet_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "network_interface_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "security_group_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "private_dns_enabled", "false"), - resource.TestCheckResourceAttr(datasourceName, "requester_managed", "false"), - resource.TestCheckResourceAttr(datasourceName, "tags.%", "0"), - acctest.CheckResourceAttrAccountID(datasourceName, "owner_id"), - acctest.MatchResourceAttrRegionalARN(datasourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(datasourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(datasourceName, "cidr_blocks.#", resourceName, "cidr_blocks.#"), + resource.TestCheckResourceAttrPair(datasourceName, "dns_entry.#", resourceName, "dns_entry.#"), + resource.TestCheckResourceAttrPair(datasourceName, "dns_options.#", resourceName, "dns_options.#"), + resource.TestCheckResourceAttrPair(datasourceName, "id", resourceName, "id"), + resource.TestCheckResourceAttrPair(datasourceName, "ip_address_type", resourceName, "ip_address_type"), + resource.TestCheckResourceAttrPair(datasourceName, "network_interface_ids.#", resourceName, "network_interface_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "owner_id", resourceName, "owner_id"), + resource.TestCheckResourceAttrPair(datasourceName, "policy", resourceName, "policy"), + resource.TestCheckResourceAttrPair(datasourceName, "prefix_list_id", resourceName, "prefix_list_id"), + resource.TestCheckResourceAttrPair(datasourceName, "private_dns_enabled", resourceName, "private_dns_enabled"), + resource.TestCheckResourceAttrPair(datasourceName, "requester_managed", resourceName, "requester_managed"), + resource.TestCheckResourceAttrPair(datasourceName, "route_table_ids.#", resourceName, "route_table_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "security_group_ids.#", resourceName, "security_group_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "service_name", resourceName, "service_name"), + resource.TestCheckResourceAttrPair(datasourceName, "state", resourceName, "state"), + resource.TestCheckResourceAttrPair(datasourceName, "subnet_ids.#", resourceName, "subnet_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "tags.%", resourceName, "tags.%"), + resource.TestCheckResourceAttrPair(datasourceName, "vpc_endpoint_type", resourceName, "vpc_endpoint_type"), + resource.TestCheckResourceAttrPair(datasourceName, "vpc_id", resourceName, "vpc_id"), ), }, }, @@ -102,6 +128,7 @@ func TestAccVPCEndpointDataSource_byFilter(t *testing.T) { } func TestAccVPCEndpointDataSource_byTags(t *testing.T) { + resourceName := "aws_vpc_endpoint.test" datasourceName := "data.aws_vpc_endpoint.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -112,19 +139,27 @@ func TestAccVPCEndpointDataSource_byTags(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccVPCEndpointDataSourceConfig_byTags(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(datasourceName, "vpc_endpoint_type", "Gateway"), - resource.TestCheckResourceAttrSet(datasourceName, "prefix_list_id"), - resource.TestCheckResourceAttrSet(datasourceName, "cidr_blocks.#"), - resource.TestCheckResourceAttr(datasourceName, "route_table_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "subnet_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "network_interface_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "security_group_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "private_dns_enabled", "false"), - resource.TestCheckResourceAttr(datasourceName, "requester_managed", "false"), - resource.TestCheckResourceAttr(datasourceName, "tags.%", "3"), - acctest.CheckResourceAttrAccountID(datasourceName, "owner_id"), - acctest.MatchResourceAttrRegionalARN(datasourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(datasourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(datasourceName, "cidr_blocks.#", resourceName, "cidr_blocks.#"), + resource.TestCheckResourceAttrPair(datasourceName, "dns_entry.#", resourceName, "dns_entry.#"), + resource.TestCheckResourceAttrPair(datasourceName, "dns_options.#", resourceName, "dns_options.#"), + resource.TestCheckResourceAttrPair(datasourceName, "id", resourceName, "id"), + resource.TestCheckResourceAttrPair(datasourceName, "ip_address_type", resourceName, "ip_address_type"), + resource.TestCheckResourceAttrPair(datasourceName, "network_interface_ids.#", resourceName, "network_interface_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "owner_id", resourceName, "owner_id"), + resource.TestCheckResourceAttrPair(datasourceName, "policy", resourceName, "policy"), + resource.TestCheckResourceAttrPair(datasourceName, "prefix_list_id", resourceName, "prefix_list_id"), + resource.TestCheckResourceAttrPair(datasourceName, "private_dns_enabled", resourceName, "private_dns_enabled"), + resource.TestCheckResourceAttrPair(datasourceName, "requester_managed", resourceName, "requester_managed"), + resource.TestCheckResourceAttrPair(datasourceName, "route_table_ids.#", resourceName, "route_table_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "security_group_ids.#", resourceName, "security_group_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "service_name", resourceName, "service_name"), + resource.TestCheckResourceAttrPair(datasourceName, "state", resourceName, "state"), + resource.TestCheckResourceAttrPair(datasourceName, "subnet_ids.#", resourceName, "subnet_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "tags.%", resourceName, "tags.%"), + resource.TestCheckResourceAttrPair(datasourceName, "vpc_endpoint_type", resourceName, "vpc_endpoint_type"), + resource.TestCheckResourceAttrPair(datasourceName, "vpc_id", resourceName, "vpc_id"), ), }, }, @@ -132,6 +167,7 @@ func TestAccVPCEndpointDataSource_byTags(t *testing.T) { } func TestAccVPCEndpointDataSource_gatewayWithRouteTableAndTags(t *testing.T) { + resourceName := "aws_vpc_endpoint.test" datasourceName := "data.aws_vpc_endpoint.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -142,20 +178,27 @@ func TestAccVPCEndpointDataSource_gatewayWithRouteTableAndTags(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccVPCEndpointDataSourceConfig_gatewayRouteTableAndTags(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(datasourceName, "vpc_endpoint_type", "Gateway"), - resource.TestCheckResourceAttrSet(datasourceName, "prefix_list_id"), - resource.TestCheckResourceAttrSet(datasourceName, "cidr_blocks.#"), - resource.TestCheckResourceAttr(datasourceName, "route_table_ids.#", "1"), - resource.TestCheckResourceAttr(datasourceName, "subnet_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "network_interface_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "security_group_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "private_dns_enabled", "false"), - resource.TestCheckResourceAttr(datasourceName, "requester_managed", "false"), - resource.TestCheckResourceAttr(datasourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(datasourceName, "tags.Name", rName), - acctest.CheckResourceAttrAccountID(datasourceName, "owner_id"), - acctest.MatchResourceAttrRegionalARN(datasourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(datasourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(datasourceName, "cidr_blocks.#", resourceName, "cidr_blocks.#"), + resource.TestCheckResourceAttrPair(datasourceName, "dns_entry.#", resourceName, "dns_entry.#"), + resource.TestCheckResourceAttrPair(datasourceName, "dns_options.#", resourceName, "dns_options.#"), + resource.TestCheckResourceAttrPair(datasourceName, "id", resourceName, "id"), + resource.TestCheckResourceAttrPair(datasourceName, "ip_address_type", resourceName, "ip_address_type"), + resource.TestCheckResourceAttrPair(datasourceName, "network_interface_ids.#", resourceName, "network_interface_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "owner_id", resourceName, "owner_id"), + resource.TestCheckResourceAttrPair(datasourceName, "policy", resourceName, "policy"), + resource.TestCheckResourceAttrPair(datasourceName, "prefix_list_id", resourceName, "prefix_list_id"), + resource.TestCheckResourceAttrPair(datasourceName, "private_dns_enabled", resourceName, "private_dns_enabled"), + resource.TestCheckResourceAttrPair(datasourceName, "requester_managed", resourceName, "requester_managed"), + resource.TestCheckResourceAttrPair(datasourceName, "route_table_ids.#", resourceName, "route_table_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "security_group_ids.#", resourceName, "security_group_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "service_name", resourceName, "service_name"), + resource.TestCheckResourceAttrPair(datasourceName, "state", resourceName, "state"), + resource.TestCheckResourceAttrPair(datasourceName, "subnet_ids.#", resourceName, "subnet_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "tags.%", resourceName, "tags.%"), + resource.TestCheckResourceAttrPair(datasourceName, "vpc_endpoint_type", resourceName, "vpc_endpoint_type"), + resource.TestCheckResourceAttrPair(datasourceName, "vpc_id", resourceName, "vpc_id"), ), }, }, @@ -163,6 +206,7 @@ func TestAccVPCEndpointDataSource_gatewayWithRouteTableAndTags(t *testing.T) { } func TestAccVPCEndpointDataSource_interface(t *testing.T) { + resourceName := "aws_vpc_endpoint.test" datasourceName := "data.aws_vpc_endpoint.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -173,20 +217,27 @@ func TestAccVPCEndpointDataSource_interface(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccVPCEndpointDataSourceConfig_interface(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(datasourceName, "vpc_endpoint_type", "Interface"), - resource.TestCheckNoResourceAttr(datasourceName, "prefix_list_id"), - resource.TestCheckResourceAttr(datasourceName, "cidr_blocks.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "route_table_ids.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "subnet_ids.#", "1"), - resource.TestCheckResourceAttr(datasourceName, "network_interface_ids.#", "1"), - resource.TestCheckResourceAttr(datasourceName, "security_group_ids.#", "1"), - resource.TestCheckResourceAttr(datasourceName, "private_dns_enabled", "false"), - resource.TestCheckResourceAttr(datasourceName, "requester_managed", "false"), - resource.TestCheckResourceAttr(datasourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(datasourceName, "tags.Name", rName), - acctest.CheckResourceAttrAccountID(datasourceName, "owner_id"), - acctest.MatchResourceAttrRegionalARN(datasourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(datasourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(datasourceName, "cidr_blocks.#", resourceName, "cidr_blocks.#"), + resource.TestCheckResourceAttrPair(datasourceName, "dns_entry.#", resourceName, "dns_entry.#"), + resource.TestCheckResourceAttrPair(datasourceName, "dns_options.#", resourceName, "dns_options.#"), + resource.TestCheckResourceAttrPair(datasourceName, "id", resourceName, "id"), + resource.TestCheckResourceAttrPair(datasourceName, "ip_address_type", resourceName, "ip_address_type"), + resource.TestCheckResourceAttrPair(datasourceName, "network_interface_ids.#", resourceName, "network_interface_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "owner_id", resourceName, "owner_id"), + resource.TestCheckResourceAttrPair(datasourceName, "policy", resourceName, "policy"), + resource.TestCheckNoResourceAttr(resourceName, "prefix_list_id"), + resource.TestCheckResourceAttrPair(datasourceName, "private_dns_enabled", resourceName, "private_dns_enabled"), + resource.TestCheckResourceAttrPair(datasourceName, "requester_managed", resourceName, "requester_managed"), + resource.TestCheckResourceAttrPair(datasourceName, "route_table_ids.#", resourceName, "route_table_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "security_group_ids.#", resourceName, "security_group_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "service_name", resourceName, "service_name"), + resource.TestCheckResourceAttrPair(datasourceName, "state", resourceName, "state"), + resource.TestCheckResourceAttrPair(datasourceName, "subnet_ids.#", resourceName, "subnet_ids.#"), + resource.TestCheckResourceAttrPair(datasourceName, "tags.%", resourceName, "tags.%"), + resource.TestCheckResourceAttrPair(datasourceName, "vpc_endpoint_type", resourceName, "vpc_endpoint_type"), + resource.TestCheckResourceAttrPair(datasourceName, "vpc_id", resourceName, "vpc_id"), ), }, }, @@ -208,6 +259,10 @@ data "aws_region" "current" {} resource "aws_vpc_endpoint" "test" { vpc_id = aws_vpc.test.id service_name = "com.amazonaws.${data.aws_region.current.name}.s3" + + tags = { + Name = %[1]q + } } data "aws_vpc_endpoint" "test" { @@ -233,6 +288,10 @@ data "aws_region" "current" {} resource "aws_vpc_endpoint" "test" { vpc_id = aws_vpc.test.id service_name = "com.amazonaws.${data.aws_region.current.name}.s3" + + tags = { + Name = %[1]q + } } data "aws_vpc_endpoint" "test" { @@ -256,6 +315,10 @@ data "aws_region" "current" {} resource "aws_vpc_endpoint" "test" { vpc_id = aws_vpc.test.id service_name = "com.amazonaws.${data.aws_region.current.name}.s3" + + tags = { + Name = %[1]q + } } data "aws_vpc_endpoint" "test" { @@ -284,6 +347,7 @@ resource "aws_vpc_endpoint" "test" { service_name = "com.amazonaws.${data.aws_region.current.name}.s3" tags = { + Name = %[1]q Key1 = "Value1" Key2 = "Value2" Key3 = "Value3" @@ -294,6 +358,7 @@ data "aws_vpc_endpoint" "test" { vpc_id = aws_vpc_endpoint.test.vpc_id tags = { + Name = %[1]q Key1 = "Value1" Key2 = "Value2" Key3 = "Value3" @@ -344,7 +409,7 @@ data "aws_vpc_endpoint" "test" { } func testAccVPCEndpointDataSourceConfig_interface(rName string) string { - return fmt.Sprintf(` + return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` resource "aws_vpc" "test" { cidr_block = "10.1.0.0/16" @@ -353,15 +418,6 @@ resource "aws_vpc" "test" { } } -data "aws_availability_zones" "available" { - state = "available" - - filter { - name = "opt-in-status" - values = ["opt-in-not-required"] - } -} - resource "aws_subnet" "test" { vpc_id = aws_vpc.test.id cidr_block = aws_vpc.test.cidr_block @@ -407,5 +463,5 @@ data "aws_vpc_endpoint" "test" { service_name = aws_vpc_endpoint.test.service_name state = "available" } -`, rName) +`, rName)) }