From 488b93b26b4a9811a4627e1b08eb791dea587894 Mon Sep 17 00:00:00 2001 From: Markos Kandylis Date: Mon, 10 Apr 2023 20:39:25 +0100 Subject: [PATCH 01/27] Created tests and vpclattice_target_group resource --- .../service/vpclattice/service_package_gen.go | 7 + internal/service/vpclattice/target_group.go | 553 ++++++++++++++++++ .../service/vpclattice/target_group_test.go | 393 +++++++++++++ 3 files changed, 953 insertions(+) create mode 100644 internal/service/vpclattice/target_group.go create mode 100644 internal/service/vpclattice/target_group_test.go diff --git a/internal/service/vpclattice/service_package_gen.go b/internal/service/vpclattice/service_package_gen.go index 055c73e83827..329efa4f05eb 100644 --- a/internal/service/vpclattice/service_package_gen.go +++ b/internal/service/vpclattice/service_package_gen.go @@ -53,6 +53,13 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka IdentifierAttribute: "arn", }, }, + { + Factory: ResourceTargetGroup, + TypeName: "aws_vpclattice_target_group", + Tags: &types.ServicePackageResourceTags{ + IdentifierAttribute: "arn", + }, + }, } } diff --git a/internal/service/vpclattice/target_group.go b/internal/service/vpclattice/target_group.go new file mode 100644 index 000000000000..e71e718e708d --- /dev/null +++ b/internal/service/vpclattice/target_group.go @@ -0,0 +1,553 @@ +package vpclattice + +import ( + "context" + "errors" + "log" + "reflect" + "strings" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/vpclattice" + "github.com/aws/aws-sdk-go-v2/service/vpclattice/types" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/internal/verify" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @SDKResource("aws_vpclattice_target_group") +// @Tags(identifierAttribute="arn") +func ResourceTargetGroup() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: resourceTargetGroupCreate, + ReadWithoutTimeout: resourceTargetGroupRead, + UpdateWithoutTimeout: resourceTargetGroupUpdate, + DeleteWithoutTimeout: resourceTargetGroupDelete, + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "client_token": { + Type: schema.TypeString, + Optional: true, + }, + "config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "health_check": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "interval": { + Type: schema.TypeInt, + Optional: true, + Default: 30, + }, + "timeout": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "healthy_threshold": { + Type: schema.TypeInt, + Optional: true, + Default: 5, + }, + "unhealthy_threshold": { + Type: schema.TypeInt, + Optional: true, + Default: 2, + }, + "matcher": { + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "path": { + Type: schema.TypeString, + Optional: true, + Default: "/", + }, + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, + "protocol": { + Type: schema.TypeString, + Optional: true, + }, + "protocol_version": { + Type: schema.TypeString, + Optional: true, + StateFunc: func(v interface{}) string { + return strings.ToUpper(v.(string)) + }, + ValidateFunc: validation.StringInSlice([]string{ + "GRPC", + "HTTP1", + "HTTP2", + }, true), + }, + }, + }, + }, + "ip_address_type": { + Type: schema.TypeString, + Optional: true, + }, + "port": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + ValidateFunc: validation.IsPortNumber, + }, + "protocol": { + Type: schema.TypeString, + Optional: true, + }, + "protocol_version": { + Type: schema.TypeString, + Optional: true, + Computed: true, + StateFunc: func(v interface{}) string { + return strings.ToUpper(v.(string)) + }, + ValidateFunc: validation.StringInSlice([]string{ + "GRPC", + "HTTP1", + "HTTP2", + }, true), + }, + "vpc_identifier": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + }, + }, + "type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), + }, + CustomizeDiff: verify.SetTagsDiff, + } +} + +const ( + ResNameTargetGroup = "Target Group" +) + +func resourceTargetGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).VPCLatticeClient() + + in := &vpclattice.CreateTargetGroupInput{ + Name: aws.String(d.Get("name").(string)), + Type: types.TargetGroupType(d.Get("type").(string)), + ClientToken: aws.String(id.UniqueId()), + Tags: GetTagsIn(ctx), + } + + if d.Get("type") != string(types.TargetGroupTypeLambda) { + if v, ok := d.GetOk("config"); ok && len(v.([]interface{})) > 0 { + config := expandConfigAttributes(v.([]interface{})[0].(map[string]interface{})) + in.Config = &types.TargetGroupConfig{ + Port: config.Port, + Protocol: config.Protocol, + VpcIdentifier: config.VpcIdentifier, + IpAddressType: config.IpAddressType, + ProtocolVersion: config.ProtocolVersion, + HealthCheck: config.HealthCheck, + } + } + } + + out, err := conn.CreateTargetGroup(ctx, in) + if err != nil { + return create.DiagError(names.VPCLattice, create.ErrActionCreating, ResNameService, d.Get("name").(string), err) + } + + if out == nil { + return create.DiagError(names.VPCLattice, create.ErrActionCreating, ResNameService, d.Get("name").(string), errors.New("empty output")) + } + + d.SetId(aws.ToString(out.Id)) + + if _, err := waitTargetGroupCreated(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return create.DiagError(names.VPCLattice, create.ErrActionWaitingForCreation, ResNameTargetGroup, d.Id(), err) + } + + return resourceTargetGroupRead(ctx, d, meta) +} + +func resourceTargetGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).VPCLatticeClient() + + out, err := FindTargetGroupByID(ctx, conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] VpcLattice TargetGroup (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return create.DiagError(names.VPCLattice, create.ErrActionReading, ResNameTargetGroup, d.Id(), err) + } + + d.Set("arn", out.Arn) + d.Set("name", out.Name) + d.Set("status", out.Status) + d.Set("type", out.Type) + if out.Config != nil { + if err := d.Set("config", flattenTargetGroupConfig(out.Config)); err != nil { + return create.DiagError(names.VPCLattice, create.ErrActionSetting, ResNameTargetGroup, d.Id(), err) + } + } else { + d.Set("config", nil) + } + + return nil +} + +func resourceTargetGroupUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).VPCLatticeClient() + + if d.HasChangesExcept("tags", "tags_all") { + in := &vpclattice.UpdateTargetGroupInput{ + TargetGroupIdentifier: aws.String(d.Id()), + } + + if d.HasChange("config") { + oldConfig, newConfig := d.GetChange("config") + oldConfigMap := expandConfigAttributes(oldConfig.([]interface{})[0].(map[string]interface{})) + newConfigMap := expandConfigAttributes(newConfig.([]interface{})[0].(map[string]interface{})) + + if !reflect.DeepEqual(oldConfigMap.HealthCheck, newConfigMap.HealthCheck) { + in.HealthCheck = newConfigMap.HealthCheck + } + } + + if in.HealthCheck == nil { + return nil + } + + log.Printf("[DEBUG] Updating VpcLattice TargetGroup (%s): %#v", d.Id(), in) + out, err := conn.UpdateTargetGroup(ctx, in) + if err != nil { + return create.DiagError(names.VPCLattice, create.ErrActionUpdating, ResNameTargetGroup, d.Id(), err) + } + + if _, err := waitTargetGroupUpdated(ctx, conn, aws.ToString(out.Id), d.Timeout(schema.TimeoutUpdate)); err != nil { + return create.DiagError(names.VPCLattice, create.ErrActionWaitingForUpdate, ResNameTargetGroup, d.Id(), err) + } + + } + + return resourceTargetGroupRead(ctx, d, meta) +} + +func resourceTargetGroupDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).VPCLatticeClient() + + log.Printf("[INFO] Deleting VpcLattice TargetGroup %s", d.Id()) + + _, err := conn.DeleteTargetGroup(ctx, &vpclattice.DeleteTargetGroupInput{ + TargetGroupIdentifier: aws.String(d.Id()), + }) + if err != nil { + var nfe *types.ResourceNotFoundException + if errors.As(err, &nfe) { + return nil + } + + return create.DiagError(names.VPCLattice, create.ErrActionDeleting, ResNameTargetGroup, d.Id(), err) + } + + if _, err := waitTargetGroupDeleted(ctx, conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { + return create.DiagError(names.VPCLattice, create.ErrActionWaitingForDeletion, ResNameTargetGroup, d.Id(), err) + } + + return nil +} + +func waitTargetGroupCreated(ctx context.Context, conn *vpclattice.Client, id string, timeout time.Duration) (*vpclattice.CreateTargetGroupOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: enum.Slice(types.TargetGroupStatusCreateInProgress), + Target: enum.Slice(types.TargetGroupStatusActive), + Refresh: statusTargetGroup(ctx, conn, id), + Timeout: timeout, + NotFoundChecks: 20, + ContinuousTargetOccurence: 2, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*vpclattice.CreateTargetGroupOutput); ok { + return out, err + } + + return nil, err +} + +func waitTargetGroupUpdated(ctx context.Context, conn *vpclattice.Client, id string, timeout time.Duration) (*vpclattice.UpdateTargetGroupOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: enum.Slice(types.TargetGroupStatusCreateInProgress), + Target: enum.Slice(types.TargetGroupStatusActive), + Refresh: statusTargetGroup(ctx, conn, id), + Timeout: timeout, + NotFoundChecks: 20, + ContinuousTargetOccurence: 2, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*vpclattice.UpdateTargetGroupOutput); ok { + return out, err + } + + return nil, err +} + +func waitTargetGroupDeleted(ctx context.Context, conn *vpclattice.Client, id string, timeout time.Duration) (*vpclattice.DeleteTargetGroupOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: enum.Slice(types.TargetGroupStatusDeleteInProgress, types.TargetGroupStatusActive), + Target: []string{}, + Refresh: statusTargetGroup(ctx, conn, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*vpclattice.DeleteTargetGroupOutput); ok { + return out, err + } + + return nil, err +} + +func statusTargetGroup(ctx context.Context, conn *vpclattice.Client, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + out, err := FindTargetGroupByID(ctx, conn, id) + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return out, string(out.Status), nil + } +} + +func FindTargetGroupByID(ctx context.Context, conn *vpclattice.Client, id string) (*vpclattice.GetTargetGroupOutput, error) { + in := &vpclattice.GetTargetGroupInput{ + TargetGroupIdentifier: aws.String(id), + } + out, err := conn.GetTargetGroup(ctx, in) + if err != nil { + var nfe *types.ResourceNotFoundException + if errors.As(err, &nfe) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: in, + } + } + + return nil, err + } + + if out == nil || out.Id == nil { + return nil, tfresource.NewEmptyResultError(in) + } + + return out, nil +} + +func flattenTargetGroupConfig(apiObject *types.TargetGroupConfig) []map[string]interface{} { + if apiObject == nil { + return nil + } + + m := map[string]interface{}{ + "port": aws.Int32(*apiObject.Port), + "protocol": string(apiObject.Protocol), + "vpc_identifier": aws.String(*apiObject.VpcIdentifier), + } + + if apiObject.IpAddressType != "" { + m["ip_address_type"] = string(apiObject.IpAddressType) + } + + if apiObject.ProtocolVersion != "" { + m["protocol_version"] = string(apiObject.ProtocolVersion) + } + + if apiObject.HealthCheck != nil { + port := *apiObject.Port + if apiObject.HealthCheck.Port != nil { + port = *apiObject.HealthCheck.Port + } + m["health_check"] = []map[string]interface{}{flattenHealthCheckConfig(apiObject.HealthCheck, port)} + } + + return []map[string]interface{}{m} +} + +func flattenHealthCheckConfig(apiObject *types.HealthCheckConfig, port int32) map[string]interface{} { + if apiObject == nil { + return nil + } + + m := map[string]interface{}{ + "enabled": aws.Bool(*apiObject.Enabled), + "interval": aws.Int32(*apiObject.HealthCheckIntervalSeconds), + "timeout": aws.Int32(*apiObject.HealthCheckTimeoutSeconds), + "healthy_threshold": aws.Int32(*apiObject.HealthyThresholdCount), + "unhealthy_threshold": aws.Int32(*apiObject.UnhealthyThresholdCount), + "path": aws.String(*apiObject.Path), + "port": aws.Int32(port), + "protocol": string(apiObject.Protocol), + "protocol_version": string(apiObject.ProtocolVersion), + } + + if matcher, ok := apiObject.Matcher.(*types.MatcherMemberHttpCode); ok { + m["matcher"] = matcher.Value + } + + return m +} + +func expandConfigAttributes(tfMap map[string]interface{}) *types.TargetGroupConfig { + if tfMap == nil { + return nil + } + apiObject := &types.TargetGroupConfig{} + + if v, ok := tfMap["port"].(int); ok { + apiObject.Port = aws.Int32(int32(v)) + } + + if v, ok := tfMap["protocol"].(string); ok { + protocol := types.TargetGroupProtocol(v) + apiObject.Protocol = protocol + } + + if v, ok := tfMap["vpc_identifier"].(string); ok { + apiObject.VpcIdentifier = aws.String(v) + } + if v, ok := tfMap["health_check"].([]interface{}); ok && len(v) > 0 { + apiObject.HealthCheck = expandHealthCheckConfigAttributes(v[0].(map[string]interface{})) + } + + if v, ok := tfMap["ip_address_type"].(string); ok { + ipAddressType := types.IpAddressType(v) + apiObject.IpAddressType = ipAddressType + } + + if v, ok := tfMap["protocol_version"].(string); ok { + protocolVersion := types.TargetGroupProtocolVersion(v) + apiObject.ProtocolVersion = protocolVersion + } + + return apiObject +} + +func expandHealthCheckConfigAttributes(tfMap map[string]interface{}) *types.HealthCheckConfig { + if tfMap == nil { + return nil + } + + apiObject := &types.HealthCheckConfig{} + + if v, ok := tfMap["enabled"].(bool); ok { + apiObject.Enabled = aws.Bool(v) + } + + if v, ok := tfMap["interval"].(int); ok { + apiObject.HealthCheckIntervalSeconds = aws.Int32(int32(v)) + } + + if v, ok := tfMap["timeout"].(int); ok { + apiObject.HealthCheckTimeoutSeconds = aws.Int32(int32(v)) + } + + if v, ok := tfMap["healthy_threshold"].(int); ok { + apiObject.HealthyThresholdCount = aws.Int32(int32(v)) + } + + if v, ok := tfMap["unhealthy_threshold"].(int); ok { + apiObject.UnhealthyThresholdCount = aws.Int32(int32(v)) + } + + if v, ok := tfMap["path"].(string); ok { + apiObject.Path = aws.String(v) + } + + if v, ok := tfMap["port"].(int); ok { + apiObject.Port = aws.Int32(int32(v)) + } + + if v, ok := tfMap["protocol"].(string); ok { + apiObject.Protocol = types.TargetGroupProtocol(v) + } + + if v, ok := tfMap["protocol_version"].(string); ok { + apiObject.ProtocolVersion = types.HealthCheckProtocolVersion(v) + } + + if v, ok := tfMap["matcher"].(string); ok { + apiObject.Matcher = &types.MatcherMemberHttpCode{Value: v} + } + + return apiObject +} diff --git a/internal/service/vpclattice/target_group_test.go b/internal/service/vpclattice/target_group_test.go new file mode 100644 index 000000000000..7fa0330e7c40 --- /dev/null +++ b/internal/service/vpclattice/target_group_test.go @@ -0,0 +1,393 @@ +package vpclattice_test + +import ( + "context" + "errors" + "fmt" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/vpclattice" + "github.com/aws/aws-sdk-go-v2/service/vpclattice/types" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "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" + "github.com/hashicorp/terraform-provider-aws/internal/create" + tfvpclattice "github.com/hashicorp/terraform-provider-aws/internal/service/vpclattice" + + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccVPCLatticeTargetGroup_basic(t *testing.T) { + ctx := acctest.Context(t) + var targetGroup vpclattice.GetTargetGroupOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_vpclattice_target_group.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.VPCLatticeEndpointID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckTargetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccVPCLatticeTargetGroupConfig_basic(rName, "INSTANCE"), + Check: resource.ComposeTestCheckFunc( + testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} +func TestAccVPCLatticeTargetGroup_full(t *testing.T) { + ctx := acctest.Context(t) + var targetGroup vpclattice.GetTargetGroupOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_vpclattice_target_group.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.VPCLatticeEndpointID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckTargetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccVPCLatticeTargetGroupConfig_fullIP(rName, "IP"), + Check: resource.ComposeTestCheckFunc( + testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "config.0.port", "443"), + resource.TestCheckResourceAttr(resourceName, "config.0.protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "config.0.ip_address_type", "IPV4"), + resource.TestCheckResourceAttr(resourceName, "config.0.protocol_version", "HTTP1"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.interval", "30"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.timeout", "5"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), + ), + }, + { + Config: testAccVPCLatticeTargetGroupConfig_fulllambda(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), + resource.TestCheckResourceAttr(resourceName, "name", rName), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), + ), + }, + { + Config: testAccVPCLatticeTargetGroupConfig_fullInstance(rName, "INSTANCE"), + Check: resource.ComposeTestCheckFunc( + testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "config.0.port", "80"), + resource.TestCheckResourceAttr(resourceName, "config.0.protocol", "HTTP"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), + ), + }, + { + Config: testAccVPCLatticeTargetGroupConfig_fullAlb(rName, "ALB"), + Check: resource.ComposeTestCheckFunc( + testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "config.0.port", "443"), + resource.TestCheckResourceAttr(resourceName, "config.0.protocol", "HTTPS"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeTargetGroup_disappears(t *testing.T) { + ctx := acctest.Context(t) + var targetGroup vpclattice.GetTargetGroupOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_vpclattice_target_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.VPCLatticeEndpointID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServiceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccVPCLatticeTargetGroupConfig_fulllambda(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), + acctest.CheckResourceDisappears(ctx, acctest.Provider, tfvpclattice.ResourceTargetGroup(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccVPCLatticeTargetGroupConfig_fulllambda(rName string) string { + return fmt.Sprintf(` + data "aws_region" "current" {} +resource "aws_vpclattice_target_group" "test" { + name = %[1]q + type = "LAMBDA" +} +`, rName) +} + +func testAccVPCLatticeTargetGroupConfig_fullIP(rName, rType string) string { + return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` +data "aws_region" "current" {} + +resource "aws_vpclattice_target_group" "test" { + name = %[1]q + type = %[2]q + config { + port = 443 + protocol = "HTTPS" + vpc_identifier = aws_vpc.test.id + ip_address_type = "IPV4" + protocol_version = "HTTP1" + health_check { + enabled = false + interval = 30 + timeout = 5 + healthy_threshold = 2 + unhealthy_threshold = 2 + matcher = "200-299" + path = "/" + port = 80 + protocol = "HTTP" + protocol_version = "HTTP1" + } + } + } + + resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + } +`, rName, rType)) +} + +func testAccVPCLatticeTargetGroupConfig_fullInstance(rName, rType string) string { + return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` +data "aws_region" "current" {} + +resource "aws_vpclattice_target_group" "test" { + name = %[1]q + type = %[2]q + config { + port = 80 + protocol = "HTTP" + vpc_identifier = aws_vpc.test.id + protocol_version = "GRPC" + health_check { + enabled = true + interval = 20 + timeout = 10 + healthy_threshold = 2 + unhealthy_threshold = 2 + matcher = "200-299" + path = "/instance" + port = 80 + protocol = "HTTP" + protocol_version = "HTTP1" + } + } + } + + resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + } +`, rName, rType)) +} + +func testAccVPCLatticeTargetGroupConfig_fullAlb(rName, rType string) string { + return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` +data "aws_region" "current" {} + +resource "aws_vpclattice_target_group" "test" { + name = %[1]q + type = %[2]q + config { + port = 443 + protocol = "HTTPS" + vpc_identifier = aws_vpc.test.id + protocol_version = "HTTP1" + } + } + + resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + } +`, rName, rType)) +} + +func testAccVPCLatticeTargetGroupConfig_basic(rName, rType string) string { + return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` +data "aws_region" "current" {} + +resource "aws_vpclattice_target_group" "test" { + name = %[1]q + type = %[2]q + config { + port = 443 + protocol = "HTTPS" + vpc_identifier = aws_vpc.test.id + } + } + + resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + } +`, rName, rType)) +} + +func TestAccVPCLatticeTargetGroup_tags(t *testing.T) { + ctx := acctest.Context(t) + var targetGroup1, targetGroup2 vpclattice.GetTargetGroupOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_vpclattice_target_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckTargetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTargetgroupConfig_tags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup1), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + Config: testAccTargetgroupConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup2), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccTargetgroupConfig_tags1(rName, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_vpclattice_target_group" "test" { + name = %[1]q + type = "LAMBDA" + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1) +} + +func testAccTargetgroupConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_vpclattice_target_group" "test" { + name = %[1]q + type = "INSTANCE" + config { + port = 80 + protocol = "HTTP" + vpc_identifier = aws_vpc.test.id + protocol_version = "HTTP1" + + } + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + } +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +} + +func testAccCheckTargetGroupDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).VPCLatticeClient() + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_vpclattice_target_group" { + continue + } + + _, err := conn.GetTargetGroup(ctx, &vpclattice.GetTargetGroupInput{ + TargetGroupIdentifier: aws.String(rs.Primary.ID), + }) + if err != nil { + var nfe *types.ResourceNotFoundException + if errors.As(err, &nfe) { + return nil + } + return err + } + + return create.Error(names.VPCLattice, create.ErrActionCheckingDestroyed, tfvpclattice.ResNameService, rs.Primary.ID, errors.New("not destroyed")) + } + + return nil + } +} + +func testAccCheckTargetGroupExists(ctx context.Context, name string, targetGroup *vpclattice.GetTargetGroupOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameService, name, errors.New("not found")) + } + + if rs.Primary.ID == "" { + return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameService, name, errors.New("not set")) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).VPCLatticeClient() + resp, err := conn.GetTargetGroup(ctx, &vpclattice.GetTargetGroupInput{ + TargetGroupIdentifier: aws.String(rs.Primary.ID), + }) + + if err != nil { + return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameService, rs.Primary.ID, err) + } + + *targetGroup = *resp + + return nil + } +} From b6457c50ce00ff7379bcaa4f7b004bda634e44f4 Mon Sep 17 00:00:00 2001 From: Markos Kandylis Date: Mon, 10 Apr 2023 21:07:50 +0100 Subject: [PATCH 02/27] added website docs file --- website/docs/r/vpclattice_target_group.html.markdown | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 website/docs/r/vpclattice_target_group.html.markdown diff --git a/website/docs/r/vpclattice_target_group.html.markdown b/website/docs/r/vpclattice_target_group.html.markdown new file mode 100644 index 000000000000..e69de29bb2d1 From ac6c87a1df4d797b5aaa7e833f95432655aad9de Mon Sep 17 00:00:00 2001 From: Markos Kandylis Date: Mon, 10 Apr 2023 21:19:06 +0100 Subject: [PATCH 03/27] added changelog --- .changelog/30455.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/30455.txt diff --git a/.changelog/30455.txt b/.changelog/30455.txt new file mode 100644 index 000000000000..feace80c8971 --- /dev/null +++ b/.changelog/30455.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_vpclattice_target_group +``` \ No newline at end of file From b32d5e2278f8244418fff6e0bc252a14df0f8594 Mon Sep 17 00:00:00 2001 From: Markos Kandylis Date: Mon, 10 Apr 2023 21:22:37 +0100 Subject: [PATCH 04/27] fixed service packages --- internal/service/vpclattice/service_package_gen.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/internal/service/vpclattice/service_package_gen.go b/internal/service/vpclattice/service_package_gen.go index 057034159043..cc7532d50d04 100644 --- a/internal/service/vpclattice/service_package_gen.go +++ b/internal/service/vpclattice/service_package_gen.go @@ -54,13 +54,8 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka }, }, { -<<<<<<< HEAD Factory: ResourceServiceNetworkVPCAssociation, TypeName: "aws_vpclattice_service_network_vpc_association", -======= - Factory: ResourceServiceNetworkServiceAssociation, - TypeName: "aws_vpclattice_service_network_service_association", ->>>>>>> f306aa08ab433bebdeddcbd3e1f2a69673610c17 Tags: &types.ServicePackageResourceTags{ IdentifierAttribute: "arn", }, From d849d974f28e5b65dcc6a3e3636db45ccc9c9e97 Mon Sep 17 00:00:00 2001 From: Markos Kandylis Date: Mon, 10 Apr 2023 21:59:40 +0100 Subject: [PATCH 05/27] pointer change --- internal/service/vpclattice/target_group.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/vpclattice/target_group.go b/internal/service/vpclattice/target_group.go index e71e718e708d..b3188742e492 100644 --- a/internal/service/vpclattice/target_group.go +++ b/internal/service/vpclattice/target_group.go @@ -433,11 +433,11 @@ func flattenTargetGroupConfig(apiObject *types.TargetGroupConfig) []map[string]i } if apiObject.HealthCheck != nil { - port := *apiObject.Port + port := apiObject.Port if apiObject.HealthCheck.Port != nil { - port = *apiObject.HealthCheck.Port + port = apiObject.HealthCheck.Port } - m["health_check"] = []map[string]interface{}{flattenHealthCheckConfig(apiObject.HealthCheck, port)} + m["health_check"] = []map[string]interface{}{flattenHealthCheckConfig(apiObject.HealthCheck, *port)} } return []map[string]interface{}{m} From 0ca0f573201e91271852806cc36bbbee62247347 Mon Sep 17 00:00:00 2001 From: Markos Kandylis Date: Mon, 10 Apr 2023 22:38:40 +0100 Subject: [PATCH 06/27] Added target group web document --- .../service/vpclattice/target_group_test.go | 1 + .../r/vpclattice_target_group.html.markdown | 128 ++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/internal/service/vpclattice/target_group_test.go b/internal/service/vpclattice/target_group_test.go index 7fa0330e7c40..55848f75535f 100644 --- a/internal/service/vpclattice/target_group_test.go +++ b/internal/service/vpclattice/target_group_test.go @@ -197,6 +197,7 @@ data "aws_region" "current" {} resource "aws_vpclattice_target_group" "test" { name = %[1]q type = %[2]q + client_token = "tstclienttoken" config { port = 80 protocol = "HTTP" diff --git a/website/docs/r/vpclattice_target_group.html.markdown b/website/docs/r/vpclattice_target_group.html.markdown index e69de29bb2d1..0b176e9e348b 100644 --- a/website/docs/r/vpclattice_target_group.html.markdown +++ b/website/docs/r/vpclattice_target_group.html.markdown @@ -0,0 +1,128 @@ +--- +subcategory: 'VPC Lattice' +layout: 'aws' +page_title: 'AWS: aws_vpclattice_target_group' +description: |- + Terraform resource for managing an AWS VPC Lattice Service. +--- + +# Resource: aws_vpclattice_target_group + +Terraform resource for managing an AWS VPC Lattice Target Group. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_vpclattice_target_group" "example" { + name = "example" + type = "INSTANCE|ALB|IP" + config { + port = 443 + protocol = "HTTPS" + vpc_identifier = aws_vpc.example.id + } + } +``` + +Basic usage with Health check + +```terraform +resource "aws_vpclattice_target_group" "example" { + name = "example" + type = "INSTANCE/ALB/IP" + client_token = "tstclienttoken" + config { + port = 443 + protocol = "HTTPS" + vpc_identifier = aws_vpc.example.id + protocol_version = "GRPC|HPPT1|HTTP2" + health_check { + enabled = true + interval = 20 + timeout = 10 + healthy_threshold = 2 + unhealthy_threshold = 2 + matcher = "200-299" + path = "/instance" + port = 80 + protocol = "HTTP" + protocol_version = "HTTP1|HTTP2" + } + } + } +``` + +If the type is Lambda config block is not required + +```terraform +resource "aws_vpclattice_target_group" "example" { + name = "example" + type = "LAMBDA" + } +``` + +## Argument Reference + +The following arguments are required: + +- `name` - (Required) The name of the target group. The name must be unique within the account. The valid characters are a-z, 0-9, and hyphens (-). You can't use a hyphen as the first or last character, or immediately after another hyphen. + +- `type` - (Required) The type of target group. Valid Values are IP | LAMBDA | INSTANCE | ALB + +- `config` - The target group configuration. If type is set to LAMBDA, this parameter doesn't apply. + +- `protocol` - (Required) The protocol to use for routing traffic to the targets. Default is the protocol of a target group. + +- `vpc_identifier` - (Required) The ID of the VPC. + +The following arguments are optional: + +- `client_token` - (Optional) A unique, case-sensitive identifier that you provide to ensure the idempotency of the request. If you retry a request that completed successfully using the same client token and parameters, the retry succeeds without performing any actions. If the parameters aren't identical, the retry fails. + +- `tags` - (Optional) Key-value mapping of resource tags. 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. + +Config (`config`) support the following: + +- `ip_address_type` - (Optional) The type of IP address used for the target group. The possible values are ipv4 and ipv6. This is an optional parameter. If not specified, the IP address type defaults to ipv4. +- `port` - (Optional) The port on which the targets are listening. For HTTP, the default is 80. For HTTPS, the default is 443. +- `protocol_version` - (Optional) The protocol version. Default value is HTTP1. Valid Values are HTTP1 | HTTP2 | GRPC +- `health_check` - (Optional) The health check configuration. + +Health Check (`health_check`) supports the following: + +- `enable` - (Optional) Indicates whether health checking is enabled. +- `interval` - (Optional) The approximate amount of time, in seconds, between health checks of an individual target. The range is 5–300 seconds. The default is 30 seconds. +- `timeout` - (Optional) The amount of time, in seconds, to wait before reporting a target as unhealthy. The range is 1–120 seconds. The default is 5 seconds. +- `healthy_threshold ` - (Optional) The number of consecutive successful health checks required before considering an unhealthy target healthy. The range is 2–10. The default is 5. +- `unhealthy_threshold` - (Optional) The number of consecutive failed health checks required before considering a target unhealthy. The range is 2–10. The default is 2. +- `matcher` - (Optional) The codes to use when checking for a successful response from a target. These are called Success codes in the console. +- `path` - (Optional) The destination for health checks on the targets. If the protocol version is HTTP/1.1 or HTTP/2, specify a valid URI (for example, /path?query). The default path is /. Health checks are not supported if the protocol version is gRPC, however, you can choose HTTP/1.1 or HTTP/2 and specify a valid URI. +- `port` - (Optional) The port used when performing health checks on targets. The default setting is the port that a target receives traffic on. +- `protocol` - (Optional) The protocol used when performing health checks on targets. The possible protocols are HTTP and HTTPS. The default is HTTP. +- `protocol_version` - (Optional) The protocol version used when performing health checks on targets. The possible protocol versions are HTTP1 and HTTP2. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +- `arn` - ARN of the target group. +- `id` - Unique identifier for the service. +- `status` - Status of the service. +- `tags_all` - Map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block). + +## Timeouts + +[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): + +- `create` - (Default `5m`) +- `delete` - (Default `5m`) + +## Import + +VPC Lattice Target Group can be imported using the `id`, e.g., + +``` +$ terraform import aws_vpclattice_service.example tg-0c11d4dc16ed96bdb +``` From 7badf12a8a9c7afe0c79dced182b0444a08559db Mon Sep 17 00:00:00 2001 From: Markos Kandylis Date: Mon, 10 Apr 2023 23:20:06 +0100 Subject: [PATCH 07/27] Formated terraform testing code --- .../service/vpclattice/target_group_test.go | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/internal/service/vpclattice/target_group_test.go b/internal/service/vpclattice/target_group_test.go index 55848f75535f..ae7d0d3948c0 100644 --- a/internal/service/vpclattice/target_group_test.go +++ b/internal/service/vpclattice/target_group_test.go @@ -148,7 +148,7 @@ func TestAccVPCLatticeTargetGroup_disappears(t *testing.T) { func testAccVPCLatticeTargetGroupConfig_fulllambda(rName string) string { return fmt.Sprintf(` - data "aws_region" "current" {} +data "aws_region" "current" {} resource "aws_vpclattice_target_group" "test" { name = %[1]q type = "LAMBDA" @@ -163,12 +163,14 @@ data "aws_region" "current" {} resource "aws_vpclattice_target_group" "test" { name = %[1]q type = %[2]q + config { port = 443 protocol = "HTTPS" vpc_identifier = aws_vpc.test.id ip_address_type = "IPV4" protocol_version = "HTTP1" + health_check { enabled = false interval = 30 @@ -195,25 +197,27 @@ func testAccVPCLatticeTargetGroupConfig_fullInstance(rName, rType string) string data "aws_region" "current" {} resource "aws_vpclattice_target_group" "test" { - name = %[1]q - type = %[2]q + name = %[1]q + type = %[2]q client_token = "tstclienttoken" + config { port = 80 protocol = "HTTP" vpc_identifier = aws_vpc.test.id protocol_version = "GRPC" + health_check { enabled = true interval = 20 timeout = 10 healthy_threshold = 2 unhealthy_threshold = 2 - matcher = "200-299" - path = "/instance" - port = 80 - protocol = "HTTP" - protocol_version = "HTTP1" + matcher = "200-299" + path = "/instance" + port = 80 + protocol = "HTTP" + protocol_version = "HTTP1" } } } @@ -231,11 +235,12 @@ data "aws_region" "current" {} resource "aws_vpclattice_target_group" "test" { name = %[1]q type = %[2]q + config { - port = 443 - protocol = "HTTPS" - vpc_identifier = aws_vpc.test.id - protocol_version = "HTTP1" + port = 443 + protocol = "HTTPS" + vpc_identifier = aws_vpc.test.id + protocol_version = "HTTP1" } } @@ -252,6 +257,7 @@ data "aws_region" "current" {} resource "aws_vpclattice_target_group" "test" { name = %[1]q type = %[2]q + config { port = 443 protocol = "HTTPS" @@ -321,12 +327,12 @@ func testAccTargetgroupConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue resource "aws_vpclattice_target_group" "test" { name = %[1]q type = "INSTANCE" + config { port = 80 protocol = "HTTP" vpc_identifier = aws_vpc.test.id protocol_version = "HTTP1" - } tags = { From d1f3af770c81cc6f271b98be563e32f442da7728 Mon Sep 17 00:00:00 2001 From: Markos Kandylis Date: Tue, 11 Apr 2023 11:04:01 +0100 Subject: [PATCH 08/27] fixed semgrep checks --- .../service/vpclattice/target_group_test.go | 40 +++++++------------ 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/internal/service/vpclattice/target_group_test.go b/internal/service/vpclattice/target_group_test.go index ae7d0d3948c0..076ffada4594 100644 --- a/internal/service/vpclattice/target_group_test.go +++ b/internal/service/vpclattice/target_group_test.go @@ -17,7 +17,6 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" tfvpclattice "github.com/hashicorp/terraform-provider-aws/internal/service/vpclattice" - "github.com/hashicorp/terraform-provider-aws/names" ) @@ -37,7 +36,7 @@ func TestAccVPCLatticeTargetGroup_basic(t *testing.T) { CheckDestroy: testAccCheckTargetGroupDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccVPCLatticeTargetGroupConfig_basic(rName, "INSTANCE"), + Config: testAccTargetGroupConfig_basic(rName, "INSTANCE"), Check: resource.ComposeTestCheckFunc( testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), @@ -67,7 +66,7 @@ func TestAccVPCLatticeTargetGroup_full(t *testing.T) { CheckDestroy: testAccCheckTargetGroupDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccVPCLatticeTargetGroupConfig_fullIP(rName, "IP"), + Config: testAccTargetGroupConfig_fullIP(rName, "IP"), Check: resource.ComposeTestCheckFunc( testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), resource.TestCheckResourceAttr(resourceName, "name", rName), @@ -82,7 +81,7 @@ func TestAccVPCLatticeTargetGroup_full(t *testing.T) { ), }, { - Config: testAccVPCLatticeTargetGroupConfig_fulllambda(rName), + Config: testAccTargetGroupConfig_fulllambda(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), resource.TestCheckResourceAttr(resourceName, "name", rName), @@ -90,7 +89,7 @@ func TestAccVPCLatticeTargetGroup_full(t *testing.T) { ), }, { - Config: testAccVPCLatticeTargetGroupConfig_fullInstance(rName, "INSTANCE"), + Config: testAccTargetGroupConfig_fullInstance(rName, "INSTANCE"), Check: resource.ComposeTestCheckFunc( testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), resource.TestCheckResourceAttr(resourceName, "name", rName), @@ -100,7 +99,7 @@ func TestAccVPCLatticeTargetGroup_full(t *testing.T) { ), }, { - Config: testAccVPCLatticeTargetGroupConfig_fullAlb(rName, "ALB"), + Config: testAccTargetGroupConfig_fullAlb(rName, "ALB"), Check: resource.ComposeTestCheckFunc( testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), resource.TestCheckResourceAttr(resourceName, "name", rName), @@ -135,7 +134,7 @@ func TestAccVPCLatticeTargetGroup_disappears(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccVPCLatticeTargetGroupConfig_fulllambda(rName), + Config: testAccTargetGroupConfig_fulllambda(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), acctest.CheckResourceDisappears(ctx, acctest.Provider, tfvpclattice.ResourceTargetGroup(), resourceName), @@ -146,9 +145,8 @@ func TestAccVPCLatticeTargetGroup_disappears(t *testing.T) { }) } -func testAccVPCLatticeTargetGroupConfig_fulllambda(rName string) string { +func testAccTargetGroupConfig_fulllambda(rName string) string { return fmt.Sprintf(` -data "aws_region" "current" {} resource "aws_vpclattice_target_group" "test" { name = %[1]q type = "LAMBDA" @@ -156,10 +154,8 @@ resource "aws_vpclattice_target_group" "test" { `, rName) } -func testAccVPCLatticeTargetGroupConfig_fullIP(rName, rType string) string { +func testAccTargetGroupConfig_fullIP(rName, rType string) string { return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` -data "aws_region" "current" {} - resource "aws_vpclattice_target_group" "test" { name = %[1]q type = %[2]q @@ -186,16 +182,14 @@ resource "aws_vpclattice_target_group" "test" { } } - resource "aws_vpc" "test" { +resource "aws_vpc" "test" { cidr_block = "10.0.0.0/16" } `, rName, rType)) } -func testAccVPCLatticeTargetGroupConfig_fullInstance(rName, rType string) string { +func testAccTargetGroupConfig_fullInstance(rName, rType string) string { return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` -data "aws_region" "current" {} - resource "aws_vpclattice_target_group" "test" { name = %[1]q type = %[2]q @@ -222,16 +216,14 @@ resource "aws_vpclattice_target_group" "test" { } } - resource "aws_vpc" "test" { +resource "aws_vpc" "test" { cidr_block = "10.0.0.0/16" } `, rName, rType)) } -func testAccVPCLatticeTargetGroupConfig_fullAlb(rName, rType string) string { +func testAccTargetGroupConfig_fullAlb(rName, rType string) string { return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` -data "aws_region" "current" {} - resource "aws_vpclattice_target_group" "test" { name = %[1]q type = %[2]q @@ -244,16 +236,14 @@ resource "aws_vpclattice_target_group" "test" { } } - resource "aws_vpc" "test" { +resource "aws_vpc" "test" { cidr_block = "10.0.0.0/16" } `, rName, rType)) } -func testAccVPCLatticeTargetGroupConfig_basic(rName, rType string) string { +func testAccTargetGroupConfig_basic(rName, rType string) string { return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` -data "aws_region" "current" {} - resource "aws_vpclattice_target_group" "test" { name = %[1]q type = %[2]q @@ -265,7 +255,7 @@ resource "aws_vpclattice_target_group" "test" { } } - resource "aws_vpc" "test" { +resource "aws_vpc" "test" { cidr_block = "10.0.0.0/16" } `, rName, rType)) From c8ec10cc1cd6fc99c3a6f3fbdc954813337c0ad7 Mon Sep 17 00:00:00 2001 From: Markos Kandylis Date: Tue, 11 Apr 2023 11:15:19 +0100 Subject: [PATCH 09/27] Fixed terrafmt --- .../service/vpclattice/target_group_test.go | 152 +++++++++--------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/internal/service/vpclattice/target_group_test.go b/internal/service/vpclattice/target_group_test.go index 076ffada4594..75bec8ee8fc3 100644 --- a/internal/service/vpclattice/target_group_test.go +++ b/internal/service/vpclattice/target_group_test.go @@ -157,107 +157,107 @@ resource "aws_vpclattice_target_group" "test" { func testAccTargetGroupConfig_fullIP(rName, rType string) string { return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` resource "aws_vpclattice_target_group" "test" { - name = %[1]q - type = %[2]q - - config { - port = 443 - protocol = "HTTPS" - vpc_identifier = aws_vpc.test.id - ip_address_type = "IPV4" - protocol_version = "HTTP1" - - health_check { - enabled = false - interval = 30 - timeout = 5 - healthy_threshold = 2 - unhealthy_threshold = 2 - matcher = "200-299" - path = "/" - port = 80 - protocol = "HTTP" - protocol_version = "HTTP1" - } - } + name = %[1]q + type = %[2]q + + config { + port = 443 + protocol = "HTTPS" + vpc_identifier = aws_vpc.test.id + ip_address_type = "IPV4" + protocol_version = "HTTP1" + + health_check { + enabled = false + interval = 30 + timeout = 5 + healthy_threshold = 2 + unhealthy_threshold = 2 + matcher = "200-299" + path = "/" + port = 80 + protocol = "HTTP" + protocol_version = "HTTP1" + } } +} resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" - } + cidr_block = "10.0.0.0/16" +} `, rName, rType)) } func testAccTargetGroupConfig_fullInstance(rName, rType string) string { return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` resource "aws_vpclattice_target_group" "test" { - name = %[1]q - type = %[2]q - client_token = "tstclienttoken" - - config { - port = 80 - protocol = "HTTP" - vpc_identifier = aws_vpc.test.id - protocol_version = "GRPC" - - health_check { - enabled = true - interval = 20 - timeout = 10 - healthy_threshold = 2 - unhealthy_threshold = 2 - matcher = "200-299" - path = "/instance" - port = 80 - protocol = "HTTP" - protocol_version = "HTTP1" - } - } + name = %[1]q + type = %[2]q + client_token = "tstclienttoken" + + config { + port = 80 + protocol = "HTTP" + vpc_identifier = aws_vpc.test.id + protocol_version = "GRPC" + + health_check { + enabled = true + interval = 20 + timeout = 10 + healthy_threshold = 2 + unhealthy_threshold = 2 + matcher = "200-299" + path = "/instance" + port = 80 + protocol = "HTTP" + protocol_version = "HTTP1" + } } +} resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" - } + cidr_block = "10.0.0.0/16" +} `, rName, rType)) } func testAccTargetGroupConfig_fullAlb(rName, rType string) string { return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` resource "aws_vpclattice_target_group" "test" { - name = %[1]q - type = %[2]q - - config { - port = 443 - protocol = "HTTPS" - vpc_identifier = aws_vpc.test.id - protocol_version = "HTTP1" - } + name = %[1]q + type = %[2]q + + config { + port = 443 + protocol = "HTTPS" + vpc_identifier = aws_vpc.test.id + protocol_version = "HTTP1" } +} resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" - } + cidr_block = "10.0.0.0/16" +} `, rName, rType)) } func testAccTargetGroupConfig_basic(rName, rType string) string { return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` resource "aws_vpclattice_target_group" "test" { - name = %[1]q - type = %[2]q + name = %[1]q + type = %[2]q - config { - port = 443 - protocol = "HTTPS" - vpc_identifier = aws_vpc.test.id - } + config { + port = 443 + protocol = "HTTPS" + vpc_identifier = aws_vpc.test.id } +} resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" - } + cidr_block = "10.0.0.0/16" +} `, rName, rType)) } @@ -319,10 +319,10 @@ resource "aws_vpclattice_target_group" "test" { type = "INSTANCE" config { - port = 80 - protocol = "HTTP" - vpc_identifier = aws_vpc.test.id - protocol_version = "HTTP1" + port = 80 + protocol = "HTTP" + vpc_identifier = aws_vpc.test.id + protocol_version = "HTTP1" } tags = { @@ -331,8 +331,8 @@ resource "aws_vpclattice_target_group" "test" { } } resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" - } + cidr_block = "10.0.0.0/16" +} `, rName, tagKey1, tagValue1, tagKey2, tagValue2) } From 6b56b8f7b3af1981546e0a409b41424b18df85d3 Mon Sep 17 00:00:00 2001 From: Markos Kandylis Date: Tue, 11 Apr 2023 11:31:22 +0100 Subject: [PATCH 10/27] Fixed Website --- .../r/vpclattice_target_group.html.markdown | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/website/docs/r/vpclattice_target_group.html.markdown b/website/docs/r/vpclattice_target_group.html.markdown index 0b176e9e348b..4fd5d45b846f 100644 --- a/website/docs/r/vpclattice_target_group.html.markdown +++ b/website/docs/r/vpclattice_target_group.html.markdown @@ -16,51 +16,51 @@ Terraform resource for managing an AWS VPC Lattice Target Group. ```terraform resource "aws_vpclattice_target_group" "example" { - name = "example" - type = "INSTANCE|ALB|IP" - config { - port = 443 - protocol = "HTTPS" - vpc_identifier = aws_vpc.example.id - } + name = "example" + type = "INSTANCE|ALB|IP" + config { + port = 443 + protocol = "HTTPS" + vpc_identifier = aws_vpc.example.id } +} ``` Basic usage with Health check ```terraform resource "aws_vpclattice_target_group" "example" { - name = "example" - type = "INSTANCE/ALB/IP" - client_token = "tstclienttoken" - config { - port = 443 - protocol = "HTTPS" - vpc_identifier = aws_vpc.example.id - protocol_version = "GRPC|HPPT1|HTTP2" - health_check { - enabled = true - interval = 20 - timeout = 10 - healthy_threshold = 2 - unhealthy_threshold = 2 - matcher = "200-299" - path = "/instance" - port = 80 - protocol = "HTTP" - protocol_version = "HTTP1|HTTP2" - } - } + name = "example" + type = "INSTANCE/ALB/IP" + client_token = "tstclienttoken" + config { + port = 443 + protocol = "HTTPS" + vpc_identifier = aws_vpc.example.id + protocol_version = "GRPC|HPPT1|HTTP2" + health_check { + enabled = true + interval = 20 + timeout = 10 + healthy_threshold = 2 + unhealthy_threshold = 2 + matcher = "200-299" + path = "/instance" + port = 80 + protocol = "HTTP" + protocol_version = "HTTP1|HTTP2" + } } +} ``` If the type is Lambda config block is not required ```terraform resource "aws_vpclattice_target_group" "example" { - name = "example" - type = "LAMBDA" - } + name = "example" + type = "LAMBDA" +} ``` ## Argument Reference From 21542a7b90cdd4bac7e414f256eafd855919aff6 Mon Sep 17 00:00:00 2001 From: Markos Kandylis Date: Tue, 11 Apr 2023 13:26:17 +0100 Subject: [PATCH 11/27] Fixed all errors from first run --- internal/service/vpclattice/target_group.go | 13 ++++++------- .../docs/r/vpclattice_target_group.html.markdown | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/internal/service/vpclattice/target_group.go b/internal/service/vpclattice/target_group.go index b3188742e492..d623a93a9f18 100644 --- a/internal/service/vpclattice/target_group.go +++ b/internal/service/vpclattice/target_group.go @@ -13,7 +13,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/vpclattice/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -292,7 +292,6 @@ func resourceTargetGroupUpdate(ctx context.Context, d *schema.ResourceData, meta if _, err := waitTargetGroupUpdated(ctx, conn, aws.ToString(out.Id), d.Timeout(schema.TimeoutUpdate)); err != nil { return create.DiagError(names.VPCLattice, create.ErrActionWaitingForUpdate, ResNameTargetGroup, d.Id(), err) } - } return resourceTargetGroupRead(ctx, d, meta) @@ -323,7 +322,7 @@ func resourceTargetGroupDelete(ctx context.Context, d *schema.ResourceData, meta } func waitTargetGroupCreated(ctx context.Context, conn *vpclattice.Client, id string, timeout time.Duration) (*vpclattice.CreateTargetGroupOutput, error) { - stateConf := &resource.StateChangeConf{ + stateConf := &retry.StateChangeConf{ Pending: enum.Slice(types.TargetGroupStatusCreateInProgress), Target: enum.Slice(types.TargetGroupStatusActive), Refresh: statusTargetGroup(ctx, conn, id), @@ -341,7 +340,7 @@ func waitTargetGroupCreated(ctx context.Context, conn *vpclattice.Client, id str } func waitTargetGroupUpdated(ctx context.Context, conn *vpclattice.Client, id string, timeout time.Duration) (*vpclattice.UpdateTargetGroupOutput, error) { - stateConf := &resource.StateChangeConf{ + stateConf := &retry.StateChangeConf{ Pending: enum.Slice(types.TargetGroupStatusCreateInProgress), Target: enum.Slice(types.TargetGroupStatusActive), Refresh: statusTargetGroup(ctx, conn, id), @@ -359,7 +358,7 @@ func waitTargetGroupUpdated(ctx context.Context, conn *vpclattice.Client, id str } func waitTargetGroupDeleted(ctx context.Context, conn *vpclattice.Client, id string, timeout time.Duration) (*vpclattice.DeleteTargetGroupOutput, error) { - stateConf := &resource.StateChangeConf{ + stateConf := &retry.StateChangeConf{ Pending: enum.Slice(types.TargetGroupStatusDeleteInProgress, types.TargetGroupStatusActive), Target: []string{}, Refresh: statusTargetGroup(ctx, conn, id), @@ -374,7 +373,7 @@ func waitTargetGroupDeleted(ctx context.Context, conn *vpclattice.Client, id str return nil, err } -func statusTargetGroup(ctx context.Context, conn *vpclattice.Client, id string) resource.StateRefreshFunc { +func statusTargetGroup(ctx context.Context, conn *vpclattice.Client, id string) retry.StateRefreshFunc { return func() (interface{}, string, error) { out, err := FindTargetGroupByID(ctx, conn, id) if tfresource.NotFound(err) { @@ -397,7 +396,7 @@ func FindTargetGroupByID(ctx context.Context, conn *vpclattice.Client, id string if err != nil { var nfe *types.ResourceNotFoundException if errors.As(err, &nfe) { - return nil, &resource.NotFoundError{ + return nil, &retry.NotFoundError{ LastError: err, LastRequest: in, } diff --git a/website/docs/r/vpclattice_target_group.html.markdown b/website/docs/r/vpclattice_target_group.html.markdown index 4fd5d45b846f..4ab8c4cb7614 100644 --- a/website/docs/r/vpclattice_target_group.html.markdown +++ b/website/docs/r/vpclattice_target_group.html.markdown @@ -3,7 +3,7 @@ subcategory: 'VPC Lattice' layout: 'aws' page_title: 'AWS: aws_vpclattice_target_group' description: |- - Terraform resource for managing an AWS VPC Lattice Service. + Terraform resource for managing an AWS VPC Lattice Target Group. --- # Resource: aws_vpclattice_target_group @@ -124,5 +124,5 @@ In addition to all arguments above, the following attributes are exported: VPC Lattice Target Group can be imported using the `id`, e.g., ``` -$ terraform import aws_vpclattice_service.example tg-0c11d4dc16ed96bdb +$ terraform import aws_vpclattice_target_group.example tg-0c11d4dc16ed96bdb ``` From d3be8571a214c76e16a8486d8157529839f525ce Mon Sep 17 00:00:00 2001 From: Markos Kandylis Date: Tue, 11 Apr 2023 14:05:00 +0100 Subject: [PATCH 12/27] removed client token as a user parameter --- internal/service/vpclattice/target_group.go | 14 +------------- internal/service/vpclattice/target_group_test.go | 5 ++--- .../docs/r/vpclattice_target_group.html.markdown | 3 --- 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/internal/service/vpclattice/target_group.go b/internal/service/vpclattice/target_group.go index d623a93a9f18..572c24302599 100644 --- a/internal/service/vpclattice/target_group.go +++ b/internal/service/vpclattice/target_group.go @@ -49,10 +49,6 @@ func ResourceTargetGroup() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "client_token": { - Type: schema.TypeString, - Optional: true, - }, "config": { Type: schema.TypeList, Optional: true, @@ -193,9 +189,9 @@ func resourceTargetGroupCreate(ctx context.Context, d *schema.ResourceData, meta conn := meta.(*conns.AWSClient).VPCLatticeClient() in := &vpclattice.CreateTargetGroupInput{ + ClientToken: aws.String(id.UniqueId()), Name: aws.String(d.Get("name").(string)), Type: types.TargetGroupType(d.Get("type").(string)), - ClientToken: aws.String(id.UniqueId()), Tags: GetTagsIn(ctx), } @@ -443,10 +439,6 @@ func flattenTargetGroupConfig(apiObject *types.TargetGroupConfig) []map[string]i } func flattenHealthCheckConfig(apiObject *types.HealthCheckConfig, port int32) map[string]interface{} { - if apiObject == nil { - return nil - } - m := map[string]interface{}{ "enabled": aws.Bool(*apiObject.Enabled), "interval": aws.Int32(*apiObject.HealthCheckIntervalSeconds), @@ -502,10 +494,6 @@ func expandConfigAttributes(tfMap map[string]interface{}) *types.TargetGroupConf } func expandHealthCheckConfigAttributes(tfMap map[string]interface{}) *types.HealthCheckConfig { - if tfMap == nil { - return nil - } - apiObject := &types.HealthCheckConfig{} if v, ok := tfMap["enabled"].(bool); ok { diff --git a/internal/service/vpclattice/target_group_test.go b/internal/service/vpclattice/target_group_test.go index 75bec8ee8fc3..164e9643a235 100644 --- a/internal/service/vpclattice/target_group_test.go +++ b/internal/service/vpclattice/target_group_test.go @@ -191,9 +191,8 @@ resource "aws_vpc" "test" { func testAccTargetGroupConfig_fullInstance(rName, rType string) string { return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` resource "aws_vpclattice_target_group" "test" { - name = %[1]q - type = %[2]q - client_token = "tstclienttoken" + name = %[1]q + type = %[2]q config { port = 80 diff --git a/website/docs/r/vpclattice_target_group.html.markdown b/website/docs/r/vpclattice_target_group.html.markdown index 4ab8c4cb7614..ce8a38e96b46 100644 --- a/website/docs/r/vpclattice_target_group.html.markdown +++ b/website/docs/r/vpclattice_target_group.html.markdown @@ -32,7 +32,6 @@ Basic usage with Health check resource "aws_vpclattice_target_group" "example" { name = "example" type = "INSTANCE/ALB/IP" - client_token = "tstclienttoken" config { port = 443 protocol = "HTTPS" @@ -79,8 +78,6 @@ The following arguments are required: The following arguments are optional: -- `client_token` - (Optional) A unique, case-sensitive identifier that you provide to ensure the idempotency of the request. If you retry a request that completed successfully using the same client token and parameters, the retry succeeds without performing any actions. If the parameters aren't identical, the retry fails. - - `tags` - (Optional) Key-value mapping of resource tags. 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. Config (`config`) support the following: From 907f4601b2b2287498335f6f610294273a8b30d3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 11 Apr 2023 13:49:03 -0400 Subject: [PATCH 13/27] r/aws_vpclattice_target_group: Modify schema to match AWS API. --- internal/service/vpclattice/target_group.go | 334 ++++++++++-------- .../r/vpclattice_target_group.html.markdown | 96 ++--- 2 files changed, 241 insertions(+), 189 deletions(-) diff --git a/internal/service/vpclattice/target_group.go b/internal/service/vpclattice/target_group.go index 572c24302599..fffcdac882ed 100644 --- a/internal/service/vpclattice/target_group.go +++ b/internal/service/vpclattice/target_group.go @@ -3,8 +3,8 @@ package vpclattice import ( "context" "errors" + "fmt" "log" - "reflect" "strings" "time" @@ -12,6 +12,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/vpclattice" "github.com/aws/aws-sdk-go-v2/service/vpclattice/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -25,7 +26,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKResource("aws_vpclattice_target_group") +// @SDKResource("aws_vpclattice_target_group", name="Target Group") // @Tags(identifierAttribute="arn") func ResourceTargetGroup() *schema.Resource { return &schema.Resource{ @@ -59,7 +60,6 @@ func ResourceTargetGroup() *schema.Resource { Type: schema.TypeList, MaxItems: 1, Optional: true, - Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "enabled": { @@ -67,30 +67,36 @@ func ResourceTargetGroup() *schema.Resource { Optional: true, Default: true, }, - "interval": { - Type: schema.TypeInt, - Optional: true, - Default: 30, - }, - "timeout": { - Type: schema.TypeInt, - Optional: true, - Computed: true, + "health_check_interval_seconds": { + Type: schema.TypeInt, + Optional: true, + Default: 30, + ValidateFunc: validation.IntBetween(5, 300), }, - "healthy_threshold": { - Type: schema.TypeInt, - Optional: true, - Default: 5, + "health_check_timeout_seconds": { + Type: schema.TypeInt, + Optional: true, + Default: 5, + ValidateFunc: validation.IntBetween(1, 120), }, - "unhealthy_threshold": { - Type: schema.TypeInt, - Optional: true, - Default: 2, + "healthy_threshold_count": { + Type: schema.TypeInt, + Optional: true, + Default: 5, + ValidateFunc: validation.IntBetween(2, 10), }, "matcher": { - Type: schema.TypeString, - Computed: true, + Type: schema.TypeList, + MaxItems: 1, Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "value": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, }, "path": { Type: schema.TypeString, @@ -100,11 +106,14 @@ func ResourceTargetGroup() *schema.Resource { "port": { Type: schema.TypeInt, Optional: true, + Computed: true, ValidateFunc: validation.IsPortNumber, }, "protocol": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + Default: types.TargetGroupProtocolHttp, + ValidateDiagFunc: enum.Validate[types.TargetGroupProtocol](), }, "protocol_version": { Type: schema.TypeString, @@ -112,41 +121,42 @@ func ResourceTargetGroup() *schema.Resource { StateFunc: func(v interface{}) string { return strings.ToUpper(v.(string)) }, - ValidateFunc: validation.StringInSlice([]string{ - "GRPC", - "HTTP1", - "HTTP2", - }, true), + ValidateDiagFunc: enum.Validate[types.HealthCheckProtocolVersion](), + }, + "unhealthy_threshold_count": { + Type: schema.TypeInt, + Optional: true, + Default: 2, + ValidateFunc: validation.IntBetween(2, 10), }, }, }, }, "ip_address_type": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + Default: types.IpAddressTypeIpv4, + ValidateDiagFunc: enum.Validate[types.IpAddressType](), }, "port": { Type: schema.TypeInt, - Optional: true, + Required: true, ForceNew: true, ValidateFunc: validation.IsPortNumber, }, "protocol": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: enum.Validate[types.TargetGroupProtocol](), }, "protocol_version": { Type: schema.TypeString, Optional: true, - Computed: true, + Default: types.TargetGroupProtocolVersionHttp1, StateFunc: func(v interface{}) string { return strings.ToUpper(v.(string)) }, - ValidateFunc: validation.StringInSlice([]string{ - "GRPC", - "HTTP1", - "HTTP2", - }, true), + ValidateDiagFunc: enum.Validate[types.TargetGroupProtocolVersion](), }, "vpc_identifier": { Type: schema.TypeString, @@ -156,28 +166,38 @@ func ResourceTargetGroup() *schema.Resource { }, }, }, - "type": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "id": { - Type: schema.TypeString, - Computed: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(3, 128), }, "status": { Type: schema.TypeString, Computed: true, }, + "type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateDiagFunc: enum.Validate[types.TargetGroupType](), + }, names.AttrTags: tftags.TagsSchema(), names.AttrTagsAll: tftags.TagsSchemaComputed(), }, - CustomizeDiff: verify.SetTagsDiff, + + CustomizeDiff: customdiff.All( + verify.SetTagsDiff, + func(ctx context.Context, d *schema.ResourceDiff, meta interface{}) error { + if v, ok := d.GetOk("config"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + if targetGroupType := types.TargetGroupType(d.Get("type").(string)); targetGroupType == types.TargetGroupTypeLambda { + return fmt.Errorf(`config not supported for type = %q`, targetGroupType) + } + } + + return nil + }, + ), } } @@ -188,34 +208,22 @@ const ( func resourceTargetGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).VPCLatticeClient() + name := d.Get("name").(string) in := &vpclattice.CreateTargetGroupInput{ ClientToken: aws.String(id.UniqueId()), - Name: aws.String(d.Get("name").(string)), - Type: types.TargetGroupType(d.Get("type").(string)), + Name: aws.String(name), Tags: GetTagsIn(ctx), + Type: types.TargetGroupType(d.Get("type").(string)), } - if d.Get("type") != string(types.TargetGroupTypeLambda) { - if v, ok := d.GetOk("config"); ok && len(v.([]interface{})) > 0 { - config := expandConfigAttributes(v.([]interface{})[0].(map[string]interface{})) - in.Config = &types.TargetGroupConfig{ - Port: config.Port, - Protocol: config.Protocol, - VpcIdentifier: config.VpcIdentifier, - IpAddressType: config.IpAddressType, - ProtocolVersion: config.ProtocolVersion, - HealthCheck: config.HealthCheck, - } - } + if v, ok := d.GetOk("config"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + in.Config = expandTargetGroupConfig(v.([]interface{})[0].(map[string]interface{})) } out, err := conn.CreateTargetGroup(ctx, in) - if err != nil { - return create.DiagError(names.VPCLattice, create.ErrActionCreating, ResNameService, d.Get("name").(string), err) - } - if out == nil { - return create.DiagError(names.VPCLattice, create.ErrActionCreating, ResNameService, d.Get("name").(string), errors.New("empty output")) + if err != nil { + return create.DiagError(names.VPCLattice, create.ErrActionCreating, ResNameService, name, err) } d.SetId(aws.ToString(out.Id)) @@ -233,7 +241,7 @@ func resourceTargetGroupRead(ctx context.Context, d *schema.ResourceData, meta i out, err := FindTargetGroupByID(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { - log.Printf("[WARN] VpcLattice TargetGroup (%s) not found, removing from state", d.Id()) + log.Printf("[WARN] VpcLattice Target Group (%s) not found, removing from state", d.Id()) d.SetId("") return nil } @@ -243,16 +251,16 @@ func resourceTargetGroupRead(ctx context.Context, d *schema.ResourceData, meta i } d.Set("arn", out.Arn) - d.Set("name", out.Name) - d.Set("status", out.Status) - d.Set("type", out.Type) if out.Config != nil { - if err := d.Set("config", flattenTargetGroupConfig(out.Config)); err != nil { + if err := d.Set("config", []interface{}{flattenTargetGroupConfig(out.Config)}); err != nil { return create.DiagError(names.VPCLattice, create.ErrActionSetting, ResNameTargetGroup, d.Id(), err) } } else { d.Set("config", nil) } + d.Set("name", out.Name) + d.Set("status", out.Status) + d.Set("type", out.Type) return nil } @@ -266,12 +274,12 @@ func resourceTargetGroupUpdate(ctx context.Context, d *schema.ResourceData, meta } if d.HasChange("config") { - oldConfig, newConfig := d.GetChange("config") - oldConfigMap := expandConfigAttributes(oldConfig.([]interface{})[0].(map[string]interface{})) - newConfigMap := expandConfigAttributes(newConfig.([]interface{})[0].(map[string]interface{})) + if v, ok := d.GetOk("config"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + config := expandTargetGroupConfig(v.([]interface{})[0].(map[string]interface{})) - if !reflect.DeepEqual(oldConfigMap.HealthCheck, newConfigMap.HealthCheck) { - in.HealthCheck = newConfigMap.HealthCheck + if v := config.HealthCheck; v != nil { + in.HealthCheck = v + } } } @@ -279,8 +287,8 @@ func resourceTargetGroupUpdate(ctx context.Context, d *schema.ResourceData, meta return nil } - log.Printf("[DEBUG] Updating VpcLattice TargetGroup (%s): %#v", d.Id(), in) out, err := conn.UpdateTargetGroup(ctx, in) + if err != nil { return create.DiagError(names.VPCLattice, create.ErrActionUpdating, ResNameTargetGroup, d.Id(), err) } @@ -296,11 +304,11 @@ func resourceTargetGroupUpdate(ctx context.Context, d *schema.ResourceData, meta func resourceTargetGroupDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).VPCLatticeClient() - log.Printf("[INFO] Deleting VpcLattice TargetGroup %s", d.Id()) - + log.Printf("[INFO] Deleting VpcLattice TargetGroup: %s", d.Id()) _, err := conn.DeleteTargetGroup(ctx, &vpclattice.DeleteTargetGroupInput{ TargetGroupIdentifier: aws.String(d.Id()), }) + if err != nil { var nfe *types.ResourceNotFoundException if errors.As(err, &nfe) { @@ -408,133 +416,173 @@ func FindTargetGroupByID(ctx context.Context, conn *vpclattice.Client, id string return out, nil } -func flattenTargetGroupConfig(apiObject *types.TargetGroupConfig) []map[string]interface{} { +func flattenTargetGroupConfig(apiObject *types.TargetGroupConfig) map[string]interface{} { if apiObject == nil { return nil } - m := map[string]interface{}{ - "port": aws.Int32(*apiObject.Port), - "protocol": string(apiObject.Protocol), - "vpc_identifier": aws.String(*apiObject.VpcIdentifier), + tfMap := map[string]interface{}{ + "ip_address_type": apiObject.IpAddressType, + "protocol": apiObject.Protocol, } - if apiObject.IpAddressType != "" { - m["ip_address_type"] = string(apiObject.IpAddressType) + if v := apiObject.HealthCheck; v != nil { + tfMap["health_check"] = []interface{}{flattenHealthCheckConfig(v)} } - if apiObject.ProtocolVersion != "" { - m["protocol_version"] = string(apiObject.ProtocolVersion) + if v := apiObject.Port; v != nil { + tfMap["port"] = aws.ToInt32(v) } - if apiObject.HealthCheck != nil { - port := apiObject.Port - if apiObject.HealthCheck.Port != nil { - port = apiObject.HealthCheck.Port - } - m["health_check"] = []map[string]interface{}{flattenHealthCheckConfig(apiObject.HealthCheck, *port)} + if v := apiObject.VpcIdentifier; v != nil { + tfMap["vpc_identifier"] = aws.ToString(v) } - return []map[string]interface{}{m} + return tfMap } -func flattenHealthCheckConfig(apiObject *types.HealthCheckConfig, port int32) map[string]interface{} { - m := map[string]interface{}{ - "enabled": aws.Bool(*apiObject.Enabled), - "interval": aws.Int32(*apiObject.HealthCheckIntervalSeconds), - "timeout": aws.Int32(*apiObject.HealthCheckTimeoutSeconds), - "healthy_threshold": aws.Int32(*apiObject.HealthyThresholdCount), - "unhealthy_threshold": aws.Int32(*apiObject.UnhealthyThresholdCount), - "path": aws.String(*apiObject.Path), - "port": aws.Int32(port), - "protocol": string(apiObject.Protocol), - "protocol_version": string(apiObject.ProtocolVersion), +func flattenHealthCheckConfig(apiObject *types.HealthCheckConfig) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{ + "protocol": apiObject.Protocol, + "protocol_version": apiObject.ProtocolVersion, + } + + if v := apiObject.Enabled; v != nil { + tfMap["enabled"] = aws.ToBool(v) + } + + if v := apiObject.HealthCheckIntervalSeconds; v != nil { + tfMap["health_check_interval_seconds"] = aws.ToInt32(v) + } + + if v := apiObject.HealthCheckTimeoutSeconds; v != nil { + tfMap["health_check_timeout_seconds"] = aws.ToInt32(v) + } + + if v := apiObject.HealthyThresholdCount; v != nil { + tfMap["healthy_threshold_count"] = aws.ToInt32(v) + } + + if v := apiObject.Matcher; v != nil { + tfMap["matcher"] = []interface{}{flattenMatcherMemberHttpCode(v.(*types.MatcherMemberHttpCode))} + } + + if v := apiObject.Path; v != nil { + tfMap["path"] = aws.ToString(v) + } + + if v := apiObject.Port; v != nil { + tfMap["port"] = aws.ToInt32(v) } - if matcher, ok := apiObject.Matcher.(*types.MatcherMemberHttpCode); ok { - m["matcher"] = matcher.Value + if v := apiObject.UnhealthyThresholdCount; v != nil { + tfMap["unhealthy_threshold_count"] = aws.ToInt32(v) } - return m + return tfMap } -func expandConfigAttributes(tfMap map[string]interface{}) *types.TargetGroupConfig { +func flattenMatcherMemberHttpCode(apiObject *types.MatcherMemberHttpCode) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{ + "value": apiObject.Value, + } + + return tfMap +} + +func expandTargetGroupConfig(tfMap map[string]interface{}) *types.TargetGroupConfig { if tfMap == nil { return nil } + apiObject := &types.TargetGroupConfig{} - if v, ok := tfMap["port"].(int); ok { - apiObject.Port = aws.Int32(int32(v)) + if v, ok := tfMap["health_check"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + apiObject.HealthCheck = expandHealthCheckConfig(v[0].(map[string]interface{})) } - if v, ok := tfMap["protocol"].(string); ok { - protocol := types.TargetGroupProtocol(v) - apiObject.Protocol = protocol + if v, ok := tfMap["ip_address_type"].(string); ok && v != "" { + apiObject.IpAddressType = types.IpAddressType(v) } - if v, ok := tfMap["vpc_identifier"].(string); ok { - apiObject.VpcIdentifier = aws.String(v) + if v, ok := tfMap["port"].(int); ok && v != 0 { + apiObject.Port = aws.Int32(int32(v)) } - if v, ok := tfMap["health_check"].([]interface{}); ok && len(v) > 0 { - apiObject.HealthCheck = expandHealthCheckConfigAttributes(v[0].(map[string]interface{})) + + if v, ok := tfMap["protocol"].(string); ok && v != "" { + apiObject.Protocol = types.TargetGroupProtocol(v) } - if v, ok := tfMap["ip_address_type"].(string); ok { - ipAddressType := types.IpAddressType(v) - apiObject.IpAddressType = ipAddressType + if v, ok := tfMap["vpc_identifier"].(string); ok && v != "" { + apiObject.VpcIdentifier = aws.String(v) } - if v, ok := tfMap["protocol_version"].(string); ok { - protocolVersion := types.TargetGroupProtocolVersion(v) - apiObject.ProtocolVersion = protocolVersion + if v, ok := tfMap["protocol_version"].(string); ok && v != "" { + apiObject.ProtocolVersion = types.TargetGroupProtocolVersion(v) } return apiObject } -func expandHealthCheckConfigAttributes(tfMap map[string]interface{}) *types.HealthCheckConfig { +func expandHealthCheckConfig(tfMap map[string]interface{}) *types.HealthCheckConfig { apiObject := &types.HealthCheckConfig{} if v, ok := tfMap["enabled"].(bool); ok { apiObject.Enabled = aws.Bool(v) } - if v, ok := tfMap["interval"].(int); ok { + if v, ok := tfMap["health_check_interval_seconds"].(int); ok && v != 0 { apiObject.HealthCheckIntervalSeconds = aws.Int32(int32(v)) } - if v, ok := tfMap["timeout"].(int); ok { + if v, ok := tfMap["health_check_timeout_seconds"].(int); ok && v != 0 { apiObject.HealthCheckTimeoutSeconds = aws.Int32(int32(v)) } - if v, ok := tfMap["healthy_threshold"].(int); ok { + if v, ok := tfMap["healthy_threshold_count"].(int); ok && v != 0 { apiObject.HealthyThresholdCount = aws.Int32(int32(v)) } - if v, ok := tfMap["unhealthy_threshold"].(int); ok { - apiObject.UnhealthyThresholdCount = aws.Int32(int32(v)) + if v, ok := tfMap["matcher"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + apiObject.Matcher = expandMatcherMemberHttpCode(v[0].(map[string]interface{})) } - if v, ok := tfMap["path"].(string); ok { + if v, ok := tfMap["path"].(string); ok && v != "" { apiObject.Path = aws.String(v) } - if v, ok := tfMap["port"].(int); ok { + if v, ok := tfMap["port"].(int); ok && v != 0 { apiObject.Port = aws.Int32(int32(v)) } - if v, ok := tfMap["protocol"].(string); ok { + if v, ok := tfMap["protocol"].(string); ok && v != "" { apiObject.Protocol = types.TargetGroupProtocol(v) } - if v, ok := tfMap["protocol_version"].(string); ok { + if v, ok := tfMap["protocol_version"].(string); ok && v != "" { apiObject.ProtocolVersion = types.HealthCheckProtocolVersion(v) } - if v, ok := tfMap["matcher"].(string); ok { - apiObject.Matcher = &types.MatcherMemberHttpCode{Value: v} + if v, ok := tfMap["unhealthy_threshold_count"].(int); ok && v != 0 { + apiObject.UnhealthyThresholdCount = aws.Int32(int32(v)) } return apiObject } + +func expandMatcherMemberHttpCode(tfMap map[string]interface{}) types.Matcher { + apiObject := &types.MatcherMemberHttpCode{} + + if v, ok := tfMap["value"].(string); ok && v != "" { + apiObject.Value = v + } + return apiObject +} diff --git a/website/docs/r/vpclattice_target_group.html.markdown b/website/docs/r/vpclattice_target_group.html.markdown index ce8a38e96b46..60d4b071bb7e 100644 --- a/website/docs/r/vpclattice_target_group.html.markdown +++ b/website/docs/r/vpclattice_target_group.html.markdown @@ -17,7 +17,7 @@ Terraform resource for managing an AWS VPC Lattice Target Group. ```terraform resource "aws_vpclattice_target_group" "example" { name = "example" - type = "INSTANCE|ALB|IP" + type = "INSTANCE" config { port = 443 protocol = "HTTPS" @@ -26,34 +26,41 @@ resource "aws_vpclattice_target_group" "example" { } ``` -Basic usage with Health check +### Basic usage with Health check ```terraform resource "aws_vpclattice_target_group" "example" { name = "example" - type = "INSTANCE/ALB/IP" + type = "ALB" config { port = 443 protocol = "HTTPS" vpc_identifier = aws_vpc.example.id - protocol_version = "GRPC|HPPT1|HTTP2" + protocol_version = "HPPT1" + health_check { - enabled = true - interval = 20 - timeout = 10 - healthy_threshold = 2 - unhealthy_threshold = 2 - matcher = "200-299" - path = "/instance" - port = 80 - protocol = "HTTP" - protocol_version = "HTTP1|HTTP2" + enabled = true + health_check_interval_seconds = 20 + health_check_timeout_seconds = 10 + healthy_threshold_count = 7 + unhealthy_threshold_count = 3 + + matcher { + value = "200-299" + } + + path = "/instance" + port = 80 + protocol = "HTTP" + protocol_version = "HTTP1" } } } ``` -If the type is Lambda config block is not required +### Lambda + +If the type is Lambda, `config` block is not supported. ```terraform resource "aws_vpclattice_target_group" "example" { @@ -66,55 +73,52 @@ resource "aws_vpclattice_target_group" "example" { The following arguments are required: -- `name` - (Required) The name of the target group. The name must be unique within the account. The valid characters are a-z, 0-9, and hyphens (-). You can't use a hyphen as the first or last character, or immediately after another hyphen. - -- `type` - (Required) The type of target group. Valid Values are IP | LAMBDA | INSTANCE | ALB - -- `config` - The target group configuration. If type is set to LAMBDA, this parameter doesn't apply. - -- `protocol` - (Required) The protocol to use for routing traffic to the targets. Default is the protocol of a target group. - -- `vpc_identifier` - (Required) The ID of the VPC. +* `name` - (Required) The name of the target group. The name must be unique within the account. The valid characters are a-z, 0-9, and hyphens (-). You can't use a hyphen as the first or last character, or immediately after another hyphen. +* `type` - (Required) The type of target group. Valid Values are `IP` | `LAMBDA` | `INSTANCE` | `ALB` The following arguments are optional: -- `tags` - (Optional) Key-value mapping of resource tags. 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. +* `config` - (Optional) The target group configuration. If type is set to `LAMBDA,` this parameter should not be specified. +* `tags` - (Optional) Key-value mapping of resource tags. 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. -Config (`config`) support the following: +Config (`config`) supports the following: -- `ip_address_type` - (Optional) The type of IP address used for the target group. The possible values are ipv4 and ipv6. This is an optional parameter. If not specified, the IP address type defaults to ipv4. -- `port` - (Optional) The port on which the targets are listening. For HTTP, the default is 80. For HTTPS, the default is 443. -- `protocol_version` - (Optional) The protocol version. Default value is HTTP1. Valid Values are HTTP1 | HTTP2 | GRPC -- `health_check` - (Optional) The health check configuration. +* `health_check` - (Optional) The health check configuration. +* `ip_address_type` - (Optional) The type of IP address used for the target group. Valid values: `IPV4` | `IPV6`. If not specified, the IP address type defaults to `IPV4`. +* `port` - (Required) The port on which the targets are listening. +* `protocol` - (Required) The protocol to use for routing traffic to the targets. Valid Values are `HTTP` | `HTTPS` +* `protocol_version` - (Optional) The protocol version. Valid Values are `HTTP1` | `HTTP2` | `GRPC`. Default value is `HTTP1`. +* `vpc_identifier` - (Optional) The ID of the VPC. Health Check (`health_check`) supports the following: -- `enable` - (Optional) Indicates whether health checking is enabled. -- `interval` - (Optional) The approximate amount of time, in seconds, between health checks of an individual target. The range is 5–300 seconds. The default is 30 seconds. -- `timeout` - (Optional) The amount of time, in seconds, to wait before reporting a target as unhealthy. The range is 1–120 seconds. The default is 5 seconds. -- `healthy_threshold ` - (Optional) The number of consecutive successful health checks required before considering an unhealthy target healthy. The range is 2–10. The default is 5. -- `unhealthy_threshold` - (Optional) The number of consecutive failed health checks required before considering a target unhealthy. The range is 2–10. The default is 2. -- `matcher` - (Optional) The codes to use when checking for a successful response from a target. These are called Success codes in the console. -- `path` - (Optional) The destination for health checks on the targets. If the protocol version is HTTP/1.1 or HTTP/2, specify a valid URI (for example, /path?query). The default path is /. Health checks are not supported if the protocol version is gRPC, however, you can choose HTTP/1.1 or HTTP/2 and specify a valid URI. -- `port` - (Optional) The port used when performing health checks on targets. The default setting is the port that a target receives traffic on. -- `protocol` - (Optional) The protocol used when performing health checks on targets. The possible protocols are HTTP and HTTPS. The default is HTTP. -- `protocol_version` - (Optional) The protocol version used when performing health checks on targets. The possible protocol versions are HTTP1 and HTTP2. +* `enabled` - (Optional) Indicates whether health checking is enabled. Defaults to `true`. +* `health_check_interval_seconds` - (Optional) The approximate amount of time, in seconds, between health checks of an individual target. The range is 5–300 seconds. The default is 30 seconds. +* `health_check_timeout_seconds` - (Optional) The amount of time, in seconds, to wait before reporting a target as unhealthy. The range is 1–120 seconds. The default is 5 seconds. +* `healthy_threshold_count ` - (Optional) The number of consecutive successful health checks required before considering an unhealthy target healthy. The range is 2–10. The default is 5. +* `matcher` - (Optional) The codes to use when checking for a successful response from a target. These are called _Success codes_ in the console. + * `value` - (Optional) The HTTP codes to use when checking for a successful response from a target. +* `path` - (Optional) The destination for health checks on the targets. If the protocol version is HTTP/1.1 or HTTP/2, specify a valid URI (for example, /path?query). The default path is `/`. Health checks are not supported if the protocol version is gRPC, however, you can choose HTTP/1.1 or HTTP/2 and specify a valid URI. +* `port` - (Optional) The port used when performing health checks on targets. The default setting is the port that a target receives traffic on. +* `protocol` - (Optional) The protocol used when performing health checks on targets. The possible protocols are `HTTP` and `HTTPS`. The default is `HTTP`. +* `protocol_version` - (Optional) The protocol version used when performing health checks on targets. The possible protocol versions are `HTTP1` and `HTTP2`. +* `unhealthy_threshold_count` - (Optional) The number of consecutive failed health checks required before considering a target unhealthy. The range is 2–10. The default is 2. ## Attributes Reference In addition to all arguments above, the following attributes are exported: -- `arn` - ARN of the target group. -- `id` - Unique identifier for the service. -- `status` - Status of the service. -- `tags_all` - Map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block). +* `arn` - ARN of the target group. +* `id` - Unique identifier for the target group. +* `status` - Status of the target group. +* `tags_all` - Map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block). ## Timeouts [Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): -- `create` - (Default `5m`) -- `delete` - (Default `5m`) +* `create` - (Default `5m`) +* `delete` - (Default `5m`) ## Import From 8df748105eeb4425967f3ea8aa55996da5a30450 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 11 Apr 2023 14:14:07 -0400 Subject: [PATCH 14/27] Fix semgrep 'ci.caps2-in-func-name'. --- internal/service/vpclattice/target_group.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/vpclattice/target_group.go b/internal/service/vpclattice/target_group.go index fffcdac882ed..37a7a9461a09 100644 --- a/internal/service/vpclattice/target_group.go +++ b/internal/service/vpclattice/target_group.go @@ -468,7 +468,7 @@ func flattenHealthCheckConfig(apiObject *types.HealthCheckConfig) map[string]int } if v := apiObject.Matcher; v != nil { - tfMap["matcher"] = []interface{}{flattenMatcherMemberHttpCode(v.(*types.MatcherMemberHttpCode))} + tfMap["matcher"] = []interface{}{flattenMatcherMemberHTTPCode(v.(*types.MatcherMemberHttpCode))} } if v := apiObject.Path; v != nil { @@ -486,7 +486,7 @@ func flattenHealthCheckConfig(apiObject *types.HealthCheckConfig) map[string]int return tfMap } -func flattenMatcherMemberHttpCode(apiObject *types.MatcherMemberHttpCode) map[string]interface{} { +func flattenMatcherMemberHTTPCode(apiObject *types.MatcherMemberHttpCode) map[string]interface{} { if apiObject == nil { return nil } @@ -552,7 +552,7 @@ func expandHealthCheckConfig(tfMap map[string]interface{}) *types.HealthCheckCon } if v, ok := tfMap["matcher"].([]interface{}); ok && len(v) > 0 && v[0] != nil { - apiObject.Matcher = expandMatcherMemberHttpCode(v[0].(map[string]interface{})) + apiObject.Matcher = expandMatcherMemberHTTPCode(v[0].(map[string]interface{})) } if v, ok := tfMap["path"].(string); ok && v != "" { @@ -578,7 +578,7 @@ func expandHealthCheckConfig(tfMap map[string]interface{}) *types.HealthCheckCon return apiObject } -func expandMatcherMemberHttpCode(tfMap map[string]interface{}) types.Matcher { +func expandMatcherMemberHTTPCode(tfMap map[string]interface{}) types.Matcher { apiObject := &types.MatcherMemberHttpCode{} if v, ok := tfMap["value"].(string); ok && v != "" { From 65be9895097b166b9f0e2ab44a9ac7c28fc8d1e3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 11 Apr 2023 14:15:05 -0400 Subject: [PATCH 15/27] Run 'make servicepackages'. --- internal/service/vpclattice/service_package_gen.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/service/vpclattice/service_package_gen.go b/internal/service/vpclattice/service_package_gen.go index cc7532d50d04..726c2a1fdc42 100644 --- a/internal/service/vpclattice/service_package_gen.go +++ b/internal/service/vpclattice/service_package_gen.go @@ -63,6 +63,7 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka { Factory: ResourceTargetGroup, TypeName: "aws_vpclattice_target_group", + Name: "Target Group", Tags: &types.ServicePackageResourceTags{ IdentifierAttribute: "arn", }, From 6eb0d0e2248e59634df3f3b37a75d9ab2f61d78a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 11 Apr 2023 14:16:24 -0400 Subject: [PATCH 16/27] Fix markdown-lint 'MD005/list-indent Inconsistent indentation for list items at the same level [Expected: 0; Actual: 1]'. --- website/docs/r/vpclattice_target_group.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/vpclattice_target_group.html.markdown b/website/docs/r/vpclattice_target_group.html.markdown index 60d4b071bb7e..05a2db340ec2 100644 --- a/website/docs/r/vpclattice_target_group.html.markdown +++ b/website/docs/r/vpclattice_target_group.html.markdown @@ -97,7 +97,7 @@ Health Check (`health_check`) supports the following: * `health_check_timeout_seconds` - (Optional) The amount of time, in seconds, to wait before reporting a target as unhealthy. The range is 1–120 seconds. The default is 5 seconds. * `healthy_threshold_count ` - (Optional) The number of consecutive successful health checks required before considering an unhealthy target healthy. The range is 2–10. The default is 5. * `matcher` - (Optional) The codes to use when checking for a successful response from a target. These are called _Success codes_ in the console. - * `value` - (Optional) The HTTP codes to use when checking for a successful response from a target. + * `value` - (Optional) The HTTP codes to use when checking for a successful response from a target. * `path` - (Optional) The destination for health checks on the targets. If the protocol version is HTTP/1.1 or HTTP/2, specify a valid URI (for example, /path?query). The default path is `/`. Health checks are not supported if the protocol version is gRPC, however, you can choose HTTP/1.1 or HTTP/2 and specify a valid URI. * `port` - (Optional) The port used when performing health checks on targets. The default setting is the port that a target receives traffic on. * `protocol` - (Optional) The protocol used when performing health checks on targets. The possible protocols are `HTTP` and `HTTPS`. The default is `HTTP`. From 7457313a92bc9924a034e1909f413a5cd31cb08e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 11 Apr 2023 14:17:18 -0400 Subject: [PATCH 17/27] Fix terrafmt errors. --- website/docs/r/vpclattice_target_group.html.markdown | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/website/docs/r/vpclattice_target_group.html.markdown b/website/docs/r/vpclattice_target_group.html.markdown index 05a2db340ec2..f6799d2d5c15 100644 --- a/website/docs/r/vpclattice_target_group.html.markdown +++ b/website/docs/r/vpclattice_target_group.html.markdown @@ -30,8 +30,9 @@ resource "aws_vpclattice_target_group" "example" { ```terraform resource "aws_vpclattice_target_group" "example" { - name = "example" - type = "ALB" + name = "example" + type = "ALB" + config { port = 443 protocol = "HTTPS" From 7fcc0ddfbb4dcd4e819a8e97b9aa105285450f9b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 11 Apr 2023 14:25:47 -0400 Subject: [PATCH 18/27] 'ValidationException: ALB Target Group must include a config'. --- internal/service/vpclattice/target_group.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/service/vpclattice/target_group.go b/internal/service/vpclattice/target_group.go index 37a7a9461a09..cc268ad02096 100644 --- a/internal/service/vpclattice/target_group.go +++ b/internal/service/vpclattice/target_group.go @@ -189,10 +189,16 @@ func ResourceTargetGroup() *schema.Resource { CustomizeDiff: customdiff.All( verify.SetTagsDiff, func(ctx context.Context, d *schema.ResourceDiff, meta interface{}) error { + targetGroupType := types.TargetGroupType(d.Get("type").(string)) + if v, ok := d.GetOk("config"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { - if targetGroupType := types.TargetGroupType(d.Get("type").(string)); targetGroupType == types.TargetGroupTypeLambda { + if targetGroupType == types.TargetGroupTypeLambda { return fmt.Errorf(`config not supported for type = %q`, targetGroupType) } + } else { + if targetGroupType != types.TargetGroupTypeLambda { + return fmt.Errorf(`config required for type = %q`, targetGroupType) + } } return nil From 0263b4ce1a716c3bc8a139f7c140c4e8ee3eb94e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 11 Apr 2023 14:29:33 -0400 Subject: [PATCH 19/27] 'config.vpc_identifier' is Required. --- internal/service/vpclattice/target_group.go | 2 +- website/docs/r/vpclattice_target_group.html.markdown | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/vpclattice/target_group.go b/internal/service/vpclattice/target_group.go index cc268ad02096..a479cf1b8a8c 100644 --- a/internal/service/vpclattice/target_group.go +++ b/internal/service/vpclattice/target_group.go @@ -160,7 +160,7 @@ func ResourceTargetGroup() *schema.Resource { }, "vpc_identifier": { Type: schema.TypeString, - Optional: true, + Required: true, ForceNew: true, }, }, diff --git a/website/docs/r/vpclattice_target_group.html.markdown b/website/docs/r/vpclattice_target_group.html.markdown index f6799d2d5c15..d8e88881ff36 100644 --- a/website/docs/r/vpclattice_target_group.html.markdown +++ b/website/docs/r/vpclattice_target_group.html.markdown @@ -89,7 +89,7 @@ Config (`config`) supports the following: * `port` - (Required) The port on which the targets are listening. * `protocol` - (Required) The protocol to use for routing traffic to the targets. Valid Values are `HTTP` | `HTTPS` * `protocol_version` - (Optional) The protocol version. Valid Values are `HTTP1` | `HTTP2` | `GRPC`. Default value is `HTTP1`. -* `vpc_identifier` - (Optional) The ID of the VPC. +* `vpc_identifier` - (Required) The ID of the VPC. Health Check (`health_check`) supports the following: From 8e1dba92ac4dff673642cc871d0912e408024e5f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 11 Apr 2023 14:58:10 -0400 Subject: [PATCH 20/27] r/aws_vpclattice_target_group: Schema fixes. --- internal/service/vpclattice/target_group.go | 38 +++++++++++++------ .../r/vpclattice_target_group.html.markdown | 2 +- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/internal/service/vpclattice/target_group.go b/internal/service/vpclattice/target_group.go index a479cf1b8a8c..a3079d5eaa4f 100644 --- a/internal/service/vpclattice/target_group.go +++ b/internal/service/vpclattice/target_group.go @@ -94,9 +94,11 @@ func ResourceTargetGroup() *schema.Resource { "value": { Type: schema.TypeString, Optional: true, + Default: "200", }, }, }, + DiffSuppressFunc: verify.SuppressMissingOptionalConfigurationBlock, }, "path": { Type: schema.TypeString, @@ -106,7 +108,6 @@ func ResourceTargetGroup() *schema.Resource { "port": { Type: schema.TypeInt, Optional: true, - Computed: true, ValidateFunc: validation.IsPortNumber, }, "protocol": { @@ -118,6 +119,7 @@ func ResourceTargetGroup() *schema.Resource { "protocol_version": { Type: schema.TypeString, Optional: true, + Default: types.HealthCheckProtocolVersionHttp1, StateFunc: func(v interface{}) string { return strings.ToUpper(v.(string)) }, @@ -131,10 +133,12 @@ func ResourceTargetGroup() *schema.Resource { }, }, }, + DiffSuppressFunc: verify.SuppressMissingOptionalConfigurationBlock, }, "ip_address_type": { Type: schema.TypeString, Optional: true, + ForceNew: true, Default: types.IpAddressTypeIpv4, ValidateDiagFunc: enum.Validate[types.IpAddressType](), }, @@ -147,11 +151,13 @@ func ResourceTargetGroup() *schema.Resource { "protocol": { Type: schema.TypeString, Required: true, + ForceNew: true, ValidateDiagFunc: enum.Validate[types.TargetGroupProtocol](), }, "protocol_version": { Type: schema.TypeString, Optional: true, + ForceNew: true, Default: types.TargetGroupProtocolVersionHttp1, StateFunc: func(v interface{}) string { return strings.ToUpper(v.(string)) @@ -428,12 +434,13 @@ func flattenTargetGroupConfig(apiObject *types.TargetGroupConfig) map[string]int } tfMap := map[string]interface{}{ - "ip_address_type": apiObject.IpAddressType, - "protocol": apiObject.Protocol, + "ip_address_type": apiObject.IpAddressType, + "protocol": apiObject.Protocol, + "protocol_version": apiObject.ProtocolVersion, } if v := apiObject.HealthCheck; v != nil { - tfMap["health_check"] = []interface{}{flattenHealthCheckConfig(v)} + tfMap["health_check"] = []interface{}{flattenHealthCheckConfig(v, apiObject.Port)} } if v := apiObject.Port; v != nil { @@ -447,7 +454,7 @@ func flattenTargetGroupConfig(apiObject *types.TargetGroupConfig) map[string]int return tfMap } -func flattenHealthCheckConfig(apiObject *types.HealthCheckConfig) map[string]interface{} { +func flattenHealthCheckConfig(apiObject *types.HealthCheckConfig, configPort *int32) map[string]interface{} { if apiObject == nil { return nil } @@ -483,6 +490,8 @@ func flattenHealthCheckConfig(apiObject *types.HealthCheckConfig) map[string]int if v := apiObject.Port; v != nil { tfMap["port"] = aws.ToInt32(v) + } else if configPort != nil { + tfMap["port"] = aws.ToInt32(configPort) } if v := apiObject.UnhealthyThresholdCount; v != nil { @@ -509,20 +518,23 @@ func expandTargetGroupConfig(tfMap map[string]interface{}) *types.TargetGroupCon return nil } - apiObject := &types.TargetGroupConfig{} + var port int32 + if v, ok := tfMap["port"].(int); ok && v != 0 { + port = int32(v) + } + + apiObject := &types.TargetGroupConfig{ + Port: aws.Int32(port), + } if v, ok := tfMap["health_check"].([]interface{}); ok && len(v) > 0 && v[0] != nil { - apiObject.HealthCheck = expandHealthCheckConfig(v[0].(map[string]interface{})) + apiObject.HealthCheck = expandHealthCheckConfig(v[0].(map[string]interface{}), port) } if v, ok := tfMap["ip_address_type"].(string); ok && v != "" { apiObject.IpAddressType = types.IpAddressType(v) } - if v, ok := tfMap["port"].(int); ok && v != 0 { - apiObject.Port = aws.Int32(int32(v)) - } - if v, ok := tfMap["protocol"].(string); ok && v != "" { apiObject.Protocol = types.TargetGroupProtocol(v) } @@ -538,7 +550,7 @@ func expandTargetGroupConfig(tfMap map[string]interface{}) *types.TargetGroupCon return apiObject } -func expandHealthCheckConfig(tfMap map[string]interface{}) *types.HealthCheckConfig { +func expandHealthCheckConfig(tfMap map[string]interface{}, configPort int32) *types.HealthCheckConfig { apiObject := &types.HealthCheckConfig{} if v, ok := tfMap["enabled"].(bool); ok { @@ -567,6 +579,8 @@ func expandHealthCheckConfig(tfMap map[string]interface{}) *types.HealthCheckCon if v, ok := tfMap["port"].(int); ok && v != 0 { apiObject.Port = aws.Int32(int32(v)) + } else { + apiObject.Port = aws.Int32(configPort) } if v, ok := tfMap["protocol"].(string); ok && v != "" { diff --git a/website/docs/r/vpclattice_target_group.html.markdown b/website/docs/r/vpclattice_target_group.html.markdown index d8e88881ff36..59915aacdef6 100644 --- a/website/docs/r/vpclattice_target_group.html.markdown +++ b/website/docs/r/vpclattice_target_group.html.markdown @@ -102,7 +102,7 @@ Health Check (`health_check`) supports the following: * `path` - (Optional) The destination for health checks on the targets. If the protocol version is HTTP/1.1 or HTTP/2, specify a valid URI (for example, /path?query). The default path is `/`. Health checks are not supported if the protocol version is gRPC, however, you can choose HTTP/1.1 or HTTP/2 and specify a valid URI. * `port` - (Optional) The port used when performing health checks on targets. The default setting is the port that a target receives traffic on. * `protocol` - (Optional) The protocol used when performing health checks on targets. The possible protocols are `HTTP` and `HTTPS`. The default is `HTTP`. -* `protocol_version` - (Optional) The protocol version used when performing health checks on targets. The possible protocol versions are `HTTP1` and `HTTP2`. +* `protocol_version` - (Optional) The protocol version used when performing health checks on targets. The possible protocol versions are `HTTP1` and `HTTP2`. The default is `HTTP1`. * `unhealthy_threshold_count` - (Optional) The number of consecutive failed health checks required before considering a target unhealthy. The range is 2–10. The default is 2. ## Attributes Reference From 60dfea891d260fe09f0476521aa50a63c70af94f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 11 Apr 2023 15:18:49 -0400 Subject: [PATCH 21/27] TestAccVPCLatticeTargetGroup_basic passing. --- internal/service/vpclattice/target_group.go | 30 +- .../service/vpclattice/target_group_test.go | 367 +++++++++--------- .../r/vpclattice_target_group.html.markdown | 4 +- 3 files changed, 207 insertions(+), 194 deletions(-) diff --git a/internal/service/vpclattice/target_group.go b/internal/service/vpclattice/target_group.go index a3079d5eaa4f..473e0efa1957 100644 --- a/internal/service/vpclattice/target_group.go +++ b/internal/service/vpclattice/target_group.go @@ -108,12 +108,13 @@ func ResourceTargetGroup() *schema.Resource { "port": { Type: schema.TypeInt, Optional: true, + Computed: true, ValidateFunc: validation.IsPortNumber, }, "protocol": { Type: schema.TypeString, Optional: true, - Default: types.TargetGroupProtocolHttp, + Computed: true, ValidateDiagFunc: enum.Validate[types.TargetGroupProtocol](), }, "protocol_version": { @@ -138,8 +139,8 @@ func ResourceTargetGroup() *schema.Resource { "ip_address_type": { Type: schema.TypeString, Optional: true, + Computed: true, ForceNew: true, - Default: types.IpAddressTypeIpv4, ValidateDiagFunc: enum.Validate[types.IpAddressType](), }, "port": { @@ -440,7 +441,7 @@ func flattenTargetGroupConfig(apiObject *types.TargetGroupConfig) map[string]int } if v := apiObject.HealthCheck; v != nil { - tfMap["health_check"] = []interface{}{flattenHealthCheckConfig(v, apiObject.Port)} + tfMap["health_check"] = []interface{}{flattenHealthCheckConfig(v)} } if v := apiObject.Port; v != nil { @@ -454,7 +455,7 @@ func flattenTargetGroupConfig(apiObject *types.TargetGroupConfig) map[string]int return tfMap } -func flattenHealthCheckConfig(apiObject *types.HealthCheckConfig, configPort *int32) map[string]interface{} { +func flattenHealthCheckConfig(apiObject *types.HealthCheckConfig) map[string]interface{} { if apiObject == nil { return nil } @@ -490,8 +491,6 @@ func flattenHealthCheckConfig(apiObject *types.HealthCheckConfig, configPort *in if v := apiObject.Port; v != nil { tfMap["port"] = aws.ToInt32(v) - } else if configPort != nil { - tfMap["port"] = aws.ToInt32(configPort) } if v := apiObject.UnhealthyThresholdCount; v != nil { @@ -518,23 +517,20 @@ func expandTargetGroupConfig(tfMap map[string]interface{}) *types.TargetGroupCon return nil } - var port int32 - if v, ok := tfMap["port"].(int); ok && v != 0 { - port = int32(v) - } - - apiObject := &types.TargetGroupConfig{ - Port: aws.Int32(port), - } + apiObject := &types.TargetGroupConfig{} if v, ok := tfMap["health_check"].([]interface{}); ok && len(v) > 0 && v[0] != nil { - apiObject.HealthCheck = expandHealthCheckConfig(v[0].(map[string]interface{}), port) + apiObject.HealthCheck = expandHealthCheckConfig(v[0].(map[string]interface{})) } if v, ok := tfMap["ip_address_type"].(string); ok && v != "" { apiObject.IpAddressType = types.IpAddressType(v) } + if v, ok := tfMap["port"].(int); ok && v != 0 { + apiObject.Port = aws.Int32(int32(v)) + } + if v, ok := tfMap["protocol"].(string); ok && v != "" { apiObject.Protocol = types.TargetGroupProtocol(v) } @@ -550,7 +546,7 @@ func expandTargetGroupConfig(tfMap map[string]interface{}) *types.TargetGroupCon return apiObject } -func expandHealthCheckConfig(tfMap map[string]interface{}, configPort int32) *types.HealthCheckConfig { +func expandHealthCheckConfig(tfMap map[string]interface{}) *types.HealthCheckConfig { apiObject := &types.HealthCheckConfig{} if v, ok := tfMap["enabled"].(bool); ok { @@ -579,8 +575,6 @@ func expandHealthCheckConfig(tfMap map[string]interface{}, configPort int32) *ty if v, ok := tfMap["port"].(int); ok && v != 0 { apiObject.Port = aws.Int32(int32(v)) - } else { - apiObject.Port = aws.Int32(configPort) } if v, ok := tfMap["protocol"].(string); ok && v != "" { diff --git a/internal/service/vpclattice/target_group_test.go b/internal/service/vpclattice/target_group_test.go index 164e9643a235..decd938bd122 100644 --- a/internal/service/vpclattice/target_group_test.go +++ b/internal/service/vpclattice/target_group_test.go @@ -25,6 +25,7 @@ func TestAccVPCLatticeTargetGroup_basic(t *testing.T) { var targetGroup vpclattice.GetTargetGroupOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_vpclattice_target_group.test" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) @@ -36,10 +37,97 @@ func TestAccVPCLatticeTargetGroup_basic(t *testing.T) { CheckDestroy: testAccCheckTargetGroupDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTargetGroupConfig_basic(rName, "INSTANCE"), - Check: resource.ComposeTestCheckFunc( + Config: testAccTargetGroupConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), + resource.TestCheckResourceAttr(resourceName, "config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.#", "1"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.health_check_interval_seconds", "30"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.health_check_timeout_seconds", "5"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.healthy_threshold_count", "5"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.matcher.#", "1"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.matcher.0.value", "200"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.path", "/"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.port", "0"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.protocol_version", "HTTP1"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.unhealthy_threshold_count", "2"), + resource.TestCheckResourceAttr(resourceName, "config.0.ip_address_type", ""), + resource.TestCheckResourceAttr(resourceName, "config.0.port", "443"), + resource.TestCheckResourceAttr(resourceName, "config.0.protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "config.0.protocol_version", "HTTP1"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "status", "ACTIVE"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "type", "INSTANCE"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeTargetGroup_disappears(t *testing.T) { + ctx := acctest.Context(t) + var targetGroup vpclattice.GetTargetGroupOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_vpclattice_target_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.VPCLatticeEndpointID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServiceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTargetGroupConfig_fulllambda(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), + acctest.CheckResourceDisappears(ctx, acctest.Provider, tfvpclattice.ResourceTargetGroup(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccVPCLatticeTargetGroup_tags(t *testing.T) { + ctx := acctest.Context(t) + var targetGroup1, targetGroup2 vpclattice.GetTargetGroupOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_vpclattice_target_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckTargetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTargetgroupConfig_tags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup1), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + Config: testAccTargetgroupConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup2), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, { @@ -50,6 +138,7 @@ func TestAccVPCLatticeTargetGroup_basic(t *testing.T) { }, }) } + func TestAccVPCLatticeTargetGroup_full(t *testing.T) { ctx := acctest.Context(t) var targetGroup vpclattice.GetTargetGroupOutput @@ -117,32 +206,109 @@ func TestAccVPCLatticeTargetGroup_full(t *testing.T) { }) } -func TestAccVPCLatticeTargetGroup_disappears(t *testing.T) { - ctx := acctest.Context(t) - var targetGroup vpclattice.GetTargetGroupOutput - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_vpclattice_target_group.test" +func testAccCheckTargetGroupDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).VPCLatticeClient() - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - acctest.PreCheckPartitionHasService(t, names.VPCLatticeEndpointID) - testAccPreCheck(ctx, t) - }, - ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckServiceDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccTargetGroupConfig_fulllambda(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), - acctest.CheckResourceDisappears(ctx, acctest.Provider, tfvpclattice.ResourceTargetGroup(), resourceName), - ), - ExpectNonEmptyPlan: true, - }, - }, - }) + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_vpclattice_target_group" { + continue + } + + _, err := conn.GetTargetGroup(ctx, &vpclattice.GetTargetGroupInput{ + TargetGroupIdentifier: aws.String(rs.Primary.ID), + }) + if err != nil { + var nfe *types.ResourceNotFoundException + if errors.As(err, &nfe) { + return nil + } + return err + } + + return create.Error(names.VPCLattice, create.ErrActionCheckingDestroyed, tfvpclattice.ResNameService, rs.Primary.ID, errors.New("not destroyed")) + } + + return nil + } +} + +func testAccCheckTargetGroupExists(ctx context.Context, name string, targetGroup *vpclattice.GetTargetGroupOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameService, name, errors.New("not found")) + } + + if rs.Primary.ID == "" { + return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameService, name, errors.New("not set")) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).VPCLatticeClient() + resp, err := conn.GetTargetGroup(ctx, &vpclattice.GetTargetGroupInput{ + TargetGroupIdentifier: aws.String(rs.Primary.ID), + }) + + if err != nil { + return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameService, rs.Primary.ID, err) + } + + *targetGroup = *resp + + return nil + } +} + +func testAccTargetGroupConfig_basic(rName string) string { + return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 0), fmt.Sprintf(` +resource "aws_vpclattice_target_group" "test" { + name = %[1]q + type = "INSTANCE" + + config { + port = 443 + protocol = "HTTPS" + vpc_identifier = aws_vpc.test.id + } +} +`, rName)) +} + +func testAccTargetgroupConfig_tags1(rName, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_vpclattice_target_group" "test" { + name = %[1]q + type = "LAMBDA" + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1) +} + +func testAccTargetgroupConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_vpclattice_target_group" "test" { + name = %[1]q + type = "INSTANCE" + + config { + port = 80 + protocol = "HTTP" + vpc_identifier = aws_vpc.test.id + protocol_version = "HTTP1" + } + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) } func testAccTargetGroupConfig_fulllambda(rName string) string { @@ -240,150 +406,3 @@ resource "aws_vpc" "test" { } `, rName, rType)) } - -func testAccTargetGroupConfig_basic(rName, rType string) string { - return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` -resource "aws_vpclattice_target_group" "test" { - name = %[1]q - type = %[2]q - - config { - port = 443 - protocol = "HTTPS" - vpc_identifier = aws_vpc.test.id - } -} - -resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" -} -`, rName, rType)) -} - -func TestAccVPCLatticeTargetGroup_tags(t *testing.T) { - ctx := acctest.Context(t) - var targetGroup1, targetGroup2 vpclattice.GetTargetGroupOutput - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_vpclattice_target_group.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckTargetGroupDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccTargetgroupConfig_tags1(rName, "key1", "value1"), - Check: resource.ComposeTestCheckFunc( - testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup1), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), - ), - }, - { - Config: testAccTargetgroupConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), - Check: resource.ComposeTestCheckFunc( - testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup2), - resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func testAccTargetgroupConfig_tags1(rName, tagKey1, tagValue1 string) string { - return fmt.Sprintf(` -resource "aws_vpclattice_target_group" "test" { - name = %[1]q - type = "LAMBDA" - - tags = { - %[2]q = %[3]q - } -} -`, rName, tagKey1, tagValue1) -} - -func testAccTargetgroupConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return fmt.Sprintf(` -resource "aws_vpclattice_target_group" "test" { - name = %[1]q - type = "INSTANCE" - - config { - port = 80 - protocol = "HTTP" - vpc_identifier = aws_vpc.test.id - protocol_version = "HTTP1" - } - - tags = { - %[2]q = %[3]q - %[4]q = %[5]q - } -} -resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" -} -`, rName, tagKey1, tagValue1, tagKey2, tagValue2) -} - -func testAccCheckTargetGroupDestroy(ctx context.Context) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).VPCLatticeClient() - - for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_vpclattice_target_group" { - continue - } - - _, err := conn.GetTargetGroup(ctx, &vpclattice.GetTargetGroupInput{ - TargetGroupIdentifier: aws.String(rs.Primary.ID), - }) - if err != nil { - var nfe *types.ResourceNotFoundException - if errors.As(err, &nfe) { - return nil - } - return err - } - - return create.Error(names.VPCLattice, create.ErrActionCheckingDestroyed, tfvpclattice.ResNameService, rs.Primary.ID, errors.New("not destroyed")) - } - - return nil - } -} - -func testAccCheckTargetGroupExists(ctx context.Context, name string, targetGroup *vpclattice.GetTargetGroupOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[name] - if !ok { - return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameService, name, errors.New("not found")) - } - - if rs.Primary.ID == "" { - return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameService, name, errors.New("not set")) - } - - conn := acctest.Provider.Meta().(*conns.AWSClient).VPCLatticeClient() - resp, err := conn.GetTargetGroup(ctx, &vpclattice.GetTargetGroupInput{ - TargetGroupIdentifier: aws.String(rs.Primary.ID), - }) - - if err != nil { - return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameService, rs.Primary.ID, err) - } - - *targetGroup = *resp - - return nil - } -} diff --git a/website/docs/r/vpclattice_target_group.html.markdown b/website/docs/r/vpclattice_target_group.html.markdown index 59915aacdef6..24d10eee6717 100644 --- a/website/docs/r/vpclattice_target_group.html.markdown +++ b/website/docs/r/vpclattice_target_group.html.markdown @@ -85,7 +85,7 @@ The following arguments are optional: Config (`config`) supports the following: * `health_check` - (Optional) The health check configuration. -* `ip_address_type` - (Optional) The type of IP address used for the target group. Valid values: `IPV4` | `IPV6`. If not specified, the IP address type defaults to `IPV4`. +* `ip_address_type` - (Optional) The type of IP address used for the target group. Valid values: `IPV4` | `IPV6` * `port` - (Required) The port on which the targets are listening. * `protocol` - (Required) The protocol to use for routing traffic to the targets. Valid Values are `HTTP` | `HTTPS` * `protocol_version` - (Optional) The protocol version. Valid Values are `HTTP1` | `HTTP2` | `GRPC`. Default value is `HTTP1`. @@ -101,7 +101,7 @@ Health Check (`health_check`) supports the following: * `value` - (Optional) The HTTP codes to use when checking for a successful response from a target. * `path` - (Optional) The destination for health checks on the targets. If the protocol version is HTTP/1.1 or HTTP/2, specify a valid URI (for example, /path?query). The default path is `/`. Health checks are not supported if the protocol version is gRPC, however, you can choose HTTP/1.1 or HTTP/2 and specify a valid URI. * `port` - (Optional) The port used when performing health checks on targets. The default setting is the port that a target receives traffic on. -* `protocol` - (Optional) The protocol used when performing health checks on targets. The possible protocols are `HTTP` and `HTTPS`. The default is `HTTP`. +* `protocol` - (Optional) The protocol used when performing health checks on targets. The possible protocols are `HTTP` and `HTTPS`. * `protocol_version` - (Optional) The protocol version used when performing health checks on targets. The possible protocol versions are `HTTP1` and `HTTP2`. The default is `HTTP1`. * `unhealthy_threshold_count` - (Optional) The number of consecutive failed health checks required before considering a target unhealthy. The range is 2–10. The default is 2. From 67e6e921a7a19bafe13732b27a7f71772ddc3708 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 11 Apr 2023 15:22:44 -0400 Subject: [PATCH 22/27] Fix "file (vpclattice_target_group.html.markdown) subcategory (subcategory: 'VPC Lattice') doesn't match file name prefix, expecting VPC Lattice". --- website/docs/r/vpclattice_target_group.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/r/vpclattice_target_group.html.markdown b/website/docs/r/vpclattice_target_group.html.markdown index 24d10eee6717..34bfabe51001 100644 --- a/website/docs/r/vpclattice_target_group.html.markdown +++ b/website/docs/r/vpclattice_target_group.html.markdown @@ -1,7 +1,7 @@ --- -subcategory: 'VPC Lattice' -layout: 'aws' -page_title: 'AWS: aws_vpclattice_target_group' +subcategory: "VPC Lattice" +layout: "aws" +page_title: "AWS: aws_vpclattice_target_group" description: |- Terraform resource for managing an AWS VPC Lattice Target Group. --- From aca528ac11ae56325e7ab4e98219cbf774e8f004 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 11 Apr 2023 15:25:56 -0400 Subject: [PATCH 23/27] Fix markdownlint 'MD007/ul-indent Unordered list indentation [Expected: 4; Actual: 2]'. --- website/docs/r/vpclattice_target_group.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/vpclattice_target_group.html.markdown b/website/docs/r/vpclattice_target_group.html.markdown index 34bfabe51001..a657e65737cc 100644 --- a/website/docs/r/vpclattice_target_group.html.markdown +++ b/website/docs/r/vpclattice_target_group.html.markdown @@ -98,7 +98,7 @@ Health Check (`health_check`) supports the following: * `health_check_timeout_seconds` - (Optional) The amount of time, in seconds, to wait before reporting a target as unhealthy. The range is 1–120 seconds. The default is 5 seconds. * `healthy_threshold_count ` - (Optional) The number of consecutive successful health checks required before considering an unhealthy target healthy. The range is 2–10. The default is 5. * `matcher` - (Optional) The codes to use when checking for a successful response from a target. These are called _Success codes_ in the console. - * `value` - (Optional) The HTTP codes to use when checking for a successful response from a target. + * `value` - (Optional) The HTTP codes to use when checking for a successful response from a target. * `path` - (Optional) The destination for health checks on the targets. If the protocol version is HTTP/1.1 or HTTP/2, specify a valid URI (for example, /path?query). The default path is `/`. Health checks are not supported if the protocol version is gRPC, however, you can choose HTTP/1.1 or HTTP/2 and specify a valid URI. * `port` - (Optional) The port used when performing health checks on targets. The default setting is the port that a target receives traffic on. * `protocol` - (Optional) The protocol used when performing health checks on targets. The possible protocols are `HTTP` and `HTTPS`. From 04f39c7bb031f9df0411959e4855717e957b44c5 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 11 Apr 2023 15:46:24 -0400 Subject: [PATCH 24/27] r/aws_vpclattice_target_group: Acceptance tests passing (so far). --- .../service/vpclattice/target_group_test.go | 228 ++++++++---------- 1 file changed, 97 insertions(+), 131 deletions(-) diff --git a/internal/service/vpclattice/target_group_test.go b/internal/service/vpclattice/target_group_test.go index decd938bd122..c016988ea443 100644 --- a/internal/service/vpclattice/target_group_test.go +++ b/internal/service/vpclattice/target_group_test.go @@ -51,12 +51,12 @@ func TestAccVPCLatticeTargetGroup_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.matcher.0.value", "200"), resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.path", "/"), resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.port", "0"), - resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.protocol", "HTTP"), resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.protocol_version", "HTTP1"), resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.unhealthy_threshold_count", "2"), resource.TestCheckResourceAttr(resourceName, "config.0.ip_address_type", ""), - resource.TestCheckResourceAttr(resourceName, "config.0.port", "443"), - resource.TestCheckResourceAttr(resourceName, "config.0.protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "config.0.port", "80"), + resource.TestCheckResourceAttr(resourceName, "config.0.protocol", "HTTP"), resource.TestCheckResourceAttr(resourceName, "config.0.protocol_version", "HTTP1"), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "status", "ACTIVE"), @@ -90,7 +90,7 @@ func TestAccVPCLatticeTargetGroup_disappears(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTargetGroupConfig_fulllambda(rName), + Config: testAccTargetGroupConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), acctest.CheckResourceDisappears(ctx, acctest.Provider, tfvpclattice.ResourceTargetGroup(), resourceName), @@ -103,7 +103,7 @@ func TestAccVPCLatticeTargetGroup_disappears(t *testing.T) { func TestAccVPCLatticeTargetGroup_tags(t *testing.T) { ctx := acctest.Context(t) - var targetGroup1, targetGroup2 vpclattice.GetTargetGroupOutput + var targetGroup vpclattice.GetTargetGroupOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_vpclattice_target_group.test" @@ -114,36 +114,45 @@ func TestAccVPCLatticeTargetGroup_tags(t *testing.T) { CheckDestroy: testAccCheckTargetGroupDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTargetgroupConfig_tags1(rName, "key1", "value1"), + Config: testAccTargetGroupConfig_tags1(rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( - testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup1), + testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), }, { - Config: testAccTargetgroupConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccTargetGroupConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup2), + testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + Config: testAccTargetGroupConfig_tags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), }, }, }) } -func TestAccVPCLatticeTargetGroup_full(t *testing.T) { +func TestAccVPCLatticeTargetGroup_lambda(t *testing.T) { ctx := acctest.Context(t) var targetGroup vpclattice.GetTargetGroupOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_vpclattice_target_group.test" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) @@ -155,46 +164,67 @@ func TestAccVPCLatticeTargetGroup_full(t *testing.T) { CheckDestroy: testAccCheckTargetGroupDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTargetGroupConfig_fullIP(rName, "IP"), - Check: resource.ComposeTestCheckFunc( + Config: testAccTargetGroupConfig_lambda(rName), + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), - resource.TestCheckResourceAttr(resourceName, "name", rName), - resource.TestCheckResourceAttr(resourceName, "config.0.port", "443"), - resource.TestCheckResourceAttr(resourceName, "config.0.protocol", "HTTPS"), - resource.TestCheckResourceAttr(resourceName, "config.0.ip_address_type", "IPV4"), - resource.TestCheckResourceAttr(resourceName, "config.0.protocol_version", "HTTP1"), - resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.enabled", "false"), - resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.interval", "30"), - resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.timeout", "5"), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), - ), - }, - { - Config: testAccTargetGroupConfig_fulllambda(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), + resource.TestCheckResourceAttr(resourceName, "config.#", "0"), resource.TestCheckResourceAttr(resourceName, "name", rName), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), + resource.TestCheckResourceAttr(resourceName, "status", "ACTIVE"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "type", "LAMBDA"), ), }, { - Config: testAccTargetGroupConfig_fullInstance(rName, "INSTANCE"), - Check: resource.ComposeTestCheckFunc( - testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), - resource.TestCheckResourceAttr(resourceName, "name", rName), - resource.TestCheckResourceAttr(resourceName, "config.0.port", "80"), - resource.TestCheckResourceAttr(resourceName, "config.0.protocol", "HTTP"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), - ), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, + }, + }) +} + +func TestAccVPCLatticeTargetGroup_ip(t *testing.T) { + ctx := acctest.Context(t) + var targetGroup vpclattice.GetTargetGroupOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_vpclattice_target_group.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.VPCLatticeEndpointID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckTargetGroupDestroy(ctx), + Steps: []resource.TestStep{ { - Config: testAccTargetGroupConfig_fullAlb(rName, "ALB"), - Check: resource.ComposeTestCheckFunc( + Config: testAccTargetGroupConfig_ip(rName), + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), - resource.TestCheckResourceAttr(resourceName, "name", rName), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), + resource.TestCheckResourceAttr(resourceName, "config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.#", "1"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.health_check_interval_seconds", "60"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.health_check_timeout_seconds", "10"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.healthy_threshold_count", "6"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.matcher.#", "1"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.matcher.0.value", "200-299"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.path", "/health"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.port", "8443"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.protocol_version", "HTTP1"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.unhealthy_threshold_count", "4"), + resource.TestCheckResourceAttr(resourceName, "config.0.ip_address_type", "IPV6"), resource.TestCheckResourceAttr(resourceName, "config.0.port", "443"), resource.TestCheckResourceAttr(resourceName, "config.0.protocol", "HTTPS"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), + resource.TestCheckResourceAttr(resourceName, "config.0.protocol_version", "HTTP2"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "status", "ACTIVE"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "type", "IP"), ), }, { @@ -266,15 +296,15 @@ resource "aws_vpclattice_target_group" "test" { type = "INSTANCE" config { - port = 443 - protocol = "HTTPS" + port = 80 + protocol = "HTTP" vpc_identifier = aws_vpc.test.id } } `, rName)) } -func testAccTargetgroupConfig_tags1(rName, tagKey1, tagValue1 string) string { +func testAccTargetGroupConfig_tags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` resource "aws_vpclattice_target_group" "test" { name = %[1]q @@ -287,31 +317,21 @@ resource "aws_vpclattice_target_group" "test" { `, rName, tagKey1, tagValue1) } -func testAccTargetgroupConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { +func testAccTargetGroupConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` resource "aws_vpclattice_target_group" "test" { name = %[1]q - type = "INSTANCE" - - config { - port = 80 - protocol = "HTTP" - vpc_identifier = aws_vpc.test.id - protocol_version = "HTTP1" - } + type = "LAMBDA" tags = { %[2]q = %[3]q %[4]q = %[5]q } } -resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" -} `, rName, tagKey1, tagValue1, tagKey2, tagValue2) } -func testAccTargetGroupConfig_fulllambda(rName string) string { +func testAccTargetGroupConfig_lambda(rName string) string { return fmt.Sprintf(` resource "aws_vpclattice_target_group" "test" { name = %[1]q @@ -320,89 +340,35 @@ resource "aws_vpclattice_target_group" "test" { `, rName) } -func testAccTargetGroupConfig_fullIP(rName, rType string) string { - return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` +func testAccTargetGroupConfig_ip(rName string) string { + return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 0), fmt.Sprintf(` resource "aws_vpclattice_target_group" "test" { name = %[1]q - type = %[2]q + type = "IP" config { port = 443 protocol = "HTTPS" vpc_identifier = aws_vpc.test.id - ip_address_type = "IPV4" - protocol_version = "HTTP1" - - health_check { - enabled = false - interval = 30 - timeout = 5 - healthy_threshold = 2 - unhealthy_threshold = 2 - matcher = "200-299" - path = "/" - port = 80 - protocol = "HTTP" - protocol_version = "HTTP1" - } - } -} - -resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" -} -`, rName, rType)) -} - -func testAccTargetGroupConfig_fullInstance(rName, rType string) string { - return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` -resource "aws_vpclattice_target_group" "test" { - name = %[1]q - type = %[2]q - - config { - port = 80 - protocol = "HTTP" - vpc_identifier = aws_vpc.test.id - protocol_version = "GRPC" + ip_address_type = "IPV6" + protocol_version = "HTTP2" health_check { - enabled = true - interval = 20 - timeout = 10 - healthy_threshold = 2 - unhealthy_threshold = 2 - matcher = "200-299" - path = "/instance" - port = 80 - protocol = "HTTP" - protocol_version = "HTTP1" + health_check_interval_seconds = 60 + health_check_timeout_seconds = 10 + healthy_threshold_count = 6 + unhealthy_threshold_count = 4 + + matcher { + value = "200-299" + } + + path = "/health" + port = 8443 + protocol = "HTTPS" + protocol_version = "HTTP1" } } } - -resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" -} -`, rName, rType)) -} - -func testAccTargetGroupConfig_fullAlb(rName, rType string) string { - return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` -resource "aws_vpclattice_target_group" "test" { - name = %[1]q - type = %[2]q - - config { - port = 443 - protocol = "HTTPS" - vpc_identifier = aws_vpc.test.id - protocol_version = "HTTP1" - } -} - -resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" -} -`, rName, rType)) +`, rName)) } From c6273062c9961e60b328141a8c29aa4b51f4f04f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 11 Apr 2023 16:12:54 -0400 Subject: [PATCH 25/27] Add 'TestAccVPCLatticeTargetGroup_alb'. --- .../service/vpclattice/target_group_test.go | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/internal/service/vpclattice/target_group_test.go b/internal/service/vpclattice/target_group_test.go index c016988ea443..04f3512ad327 100644 --- a/internal/service/vpclattice/target_group_test.go +++ b/internal/service/vpclattice/target_group_test.go @@ -232,6 +232,87 @@ func TestAccVPCLatticeTargetGroup_ip(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + Config: testAccTargetGroupConfig_ipUpdated(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), + resource.TestCheckResourceAttr(resourceName, "config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.#", "1"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.health_check_interval_seconds", "180"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.health_check_timeout_seconds", "90"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.healthy_threshold_count", "8"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.matcher.#", "1"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.matcher.0.value", "202"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.path", "/health"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.port", "8443"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.protocol_version", "HTTP2"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.unhealthy_threshold_count", "3"), + resource.TestCheckResourceAttr(resourceName, "config.0.ip_address_type", "IPV6"), + resource.TestCheckResourceAttr(resourceName, "config.0.port", "443"), + resource.TestCheckResourceAttr(resourceName, "config.0.protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "config.0.protocol_version", "HTTP2"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "status", "ACTIVE"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "type", "IP"), + ), + }, + }, + }) +} + +func TestAccVPCLatticeTargetGroup_alb(t *testing.T) { + ctx := acctest.Context(t) + var targetGroup vpclattice.GetTargetGroupOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_vpclattice_target_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.VPCLatticeEndpointID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckTargetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTargetGroupConfig_alb(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), + resource.TestCheckResourceAttr(resourceName, "config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.#", "1"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.health_check_interval_seconds", "30"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.health_check_timeout_seconds", "5"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.healthy_threshold_count", "5"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.matcher.#", "1"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.matcher.0.value", "200"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.path", "/"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.port", "0"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.protocol", "HTTP"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.protocol_version", "HTTP1"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.unhealthy_threshold_count", "2"), + resource.TestCheckResourceAttr(resourceName, "config.0.ip_address_type", ""), + resource.TestCheckResourceAttr(resourceName, "config.0.port", "80"), + resource.TestCheckResourceAttr(resourceName, "config.0.protocol", "HTTP"), + resource.TestCheckResourceAttr(resourceName, "config.0.protocol_version", "HTTP1"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "status", "ACTIVE"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "type", "ALB"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -372,3 +453,51 @@ resource "aws_vpclattice_target_group" "test" { } `, rName)) } + +func testAccTargetGroupConfig_ipUpdated(rName string) string { + return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 0), fmt.Sprintf(` +resource "aws_vpclattice_target_group" "test" { + name = %[1]q + type = "IP" + + config { + port = 443 + protocol = "HTTPS" + vpc_identifier = aws_vpc.test.id + ip_address_type = "IPV6" + protocol_version = "HTTP2" + + health_check { + health_check_interval_seconds = 180 + health_check_timeout_seconds = 90 + healthy_threshold_count = 8 + unhealthy_threshold_count = 3 + + matcher { + value = "202" + } + + path = "/health" + port = 8443 + protocol = "HTTPS" + protocol_version = "HTTP2" + } + } +} +`, rName)) +} + +func testAccTargetGroupConfig_alb(rName string) string { + return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 0), fmt.Sprintf(` +resource "aws_vpclattice_target_group" "test" { + name = %[1]q + type = "ALB" + + config { + port = 80 + protocol = "HTTP" + vpc_identifier = aws_vpc.test.id + } +} +`, rName)) +} From 29d92d4358ca465b1b68b7e1a02c49bc12ce229f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 11 Apr 2023 16:14:00 -0400 Subject: [PATCH 26/27] Fix terrafmt errors. --- internal/service/vpclattice/target_group_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/vpclattice/target_group_test.go b/internal/service/vpclattice/target_group_test.go index 04f3512ad327..217c94df2933 100644 --- a/internal/service/vpclattice/target_group_test.go +++ b/internal/service/vpclattice/target_group_test.go @@ -442,7 +442,7 @@ resource "aws_vpclattice_target_group" "test" { matcher { value = "200-299" - } + } path = "/health" port = 8443 @@ -475,7 +475,7 @@ resource "aws_vpclattice_target_group" "test" { matcher { value = "202" - } + } path = "/health" port = 8443 From 3e744e0386c8e6c300a21397c4a49dfd4f27bf9c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 11 Apr 2023 16:17:58 -0400 Subject: [PATCH 27/27] Correct 'TestAccVPCLatticeTargetGroup_alb'. --- internal/service/vpclattice/target_group_test.go | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/internal/service/vpclattice/target_group_test.go b/internal/service/vpclattice/target_group_test.go index 217c94df2933..526b832534eb 100644 --- a/internal/service/vpclattice/target_group_test.go +++ b/internal/service/vpclattice/target_group_test.go @@ -286,18 +286,7 @@ func TestAccVPCLatticeTargetGroup_alb(t *testing.T) { testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), resource.TestCheckResourceAttr(resourceName, "config.#", "1"), - resource.TestCheckResourceAttr(resourceName, "config.0.health_check.#", "1"), - resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.enabled", "true"), - resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.health_check_interval_seconds", "30"), - resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.health_check_timeout_seconds", "5"), - resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.healthy_threshold_count", "5"), - resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.matcher.#", "1"), - resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.matcher.0.value", "200"), - resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.path", "/"), - resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.port", "0"), - resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.protocol", "HTTP"), - resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.protocol_version", "HTTP1"), - resource.TestCheckResourceAttr(resourceName, "config.0.health_check.0.unhealthy_threshold_count", "2"), + resource.TestCheckResourceAttr(resourceName, "config.0.health_check.#", "0"), resource.TestCheckResourceAttr(resourceName, "config.0.ip_address_type", ""), resource.TestCheckResourceAttr(resourceName, "config.0.port", "80"), resource.TestCheckResourceAttr(resourceName, "config.0.protocol", "HTTP"),