From 2488f5ecc1980f430549f87b384e9eefebfca799 Mon Sep 17 00:00:00 2001 From: Markos Kandylis Date: Mon, 24 Apr 2023 23:24:55 +0100 Subject: [PATCH 01/17] Initial code with expand and flateners --- .../service/vpclattice/register_targets.go | 258 ++++++++++++++++++ .../vpclattice/register_targets_test.go | 120 ++++++++ .../service/vpclattice/service_package_gen.go | 5 + .../vpclattice_register_targets.html.markdown | 53 ++++ 4 files changed, 436 insertions(+) create mode 100644 internal/service/vpclattice/register_targets.go create mode 100644 internal/service/vpclattice/register_targets_test.go create mode 100644 website/docs/r/vpclattice_register_targets.html.markdown diff --git a/internal/service/vpclattice/register_targets.go b/internal/service/vpclattice/register_targets.go new file mode 100644 index 000000000000..1a2ae6f551a5 --- /dev/null +++ b/internal/service/vpclattice/register_targets.go @@ -0,0 +1,258 @@ +package vpclattice + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "log" + "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/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" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// Function annotations are used for resource registration to the Provider. DO NOT EDIT. +// @SDKResource("aws_vpclattice_register_targets", name="Register Targets") +func ResourceRegisterTargets() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: resourceRegisterTargetsCreate, + ReadWithoutTimeout: resourceRegisterTargetsRead, + UpdateWithoutTimeout: resourceRegisterTargetsUpdate, + DeleteWithoutTimeout: resourceRegisterTargetsDelete, + + 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{ + "target_group_identifier": { + Type: schema.TypeString, + Required: true, + }, + "targets": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 2048), + }, + "port": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + }, + } +} + +const ( + ResNameRegisterTargets = "Register Targets" +) + +func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).VPCLatticeClient() + in := &vpclattice.RegisterTargetsInput{ + TargetGroupIdentifier: aws.String(d.Get("target_group_identifier").(string)), + } + + if v, ok := d.GetOk("targets"); ok && len(v.([]interface{})) > 0 && v.([]interface{}) != nil { + in.Targets = expandTargets(v.([]interface{})) + } + + out, err := conn.RegisterTargets(ctx, in) + if err != nil { + return create.DiagError(names.VPCLattice, create.ErrActionCreating, ResNameRegisterTargets, "id", err) + } + + if out == nil { + return create.DiagError(names.VPCLattice, create.ErrActionCreating, ResNameRegisterTargets, "id", errors.New("empty output")) + } + + d.SetId(aws.ToString(in.TargetGroupIdentifier)) + // d.SetId(id.PrefixedUniqueId(fmt.Sprintf("%s-", d.Get("target_group_identifier")))) + + return resourceRegisterTargetsRead(ctx, d, meta) +} + +func resourceRegisterTargetsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + fmt.Println("I am at read") + conn := meta.(*conns.AWSClient).VPCLatticeClient() + + targetGroupIdentifier := d.Get("target_group_identifier").(string) + fmt.Println(targetGroupIdentifier) + out, err := findRegisterTargets(ctx, conn, targetGroupIdentifier) + fmt.Println(d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] VpcLattice RegisterTargets (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return create.DiagError(names.VPCLattice, create.ErrActionReading, ResNameRegisterTargets, d.Id(), err) + } + + // if err := d.Set("targets", []interface{}{flattenTargets(out.Items)}); err != nil { + // return create.DiagError(names.VPCLattice, create.ErrActionSetting, ResNameRegisterTargets, d.Id(), err) + // } + if err := d.Set("targets", flattenTargets(out.Items)); err != nil { + return diag.FromErr(fmt.Errorf("error setting targets: %s", err)) + } + + return nil +} + +func resourceRegisterTargetsUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + return resourceRegisterTargetsRead(ctx, d, meta) +} + +func resourceRegisterTargetsDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + + conn := meta.(*conns.AWSClient).VPCLatticeClient() + + log.Printf("[INFO] Deleting VpcLattice RegisterTargets %s", d.Id()) + targetGroupIdentifier := d.Get("target_group_identifier").(string) + targetsRaw := d.Get("targets").([]interface{}) + targets := expandTargets(targetsRaw) + + _, err := conn.DeregisterTargets(ctx, &vpclattice.DeregisterTargetsInput{ + TargetGroupIdentifier: aws.String(targetGroupIdentifier), + Targets: targets, + }) + + if err != nil { + var nfe *types.ResourceNotFoundException + if errors.As(err, &nfe) { + return nil + } + + return create.DiagError(names.VPCLattice, create.ErrActionDeleting, ResNameRegisterTargets, d.Id(), err) + } + + return nil +} + +func findRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string) (*vpclattice.ListTargetsOutput, error) { + fmt.Println("I am at find") + in := &vpclattice.ListTargetsInput{ + TargetGroupIdentifier: aws.String(id), + } + out, err := conn.ListTargets(ctx, in) + if err != nil { + var nfe *types.ResourceNotFoundException + if errors.As(err, &nfe) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: in, + } + } + + return nil, err + } + + if out == nil || out.Items == nil { + return nil, tfresource.NewEmptyResultError(in) + } + + return out, nil +} + +func flattenTargets(apiObjects []types.TargetSummary) []interface{} { + if len(apiObjects) == 0 { + return nil + } + + var tfList []interface{} + + for _, apiObject := range apiObjects { + fmt.Printf("[DEBUG] flattenTargets - apiObject: %#v\n", apiObject) + tfList = append(tfList, flattenTarget(&apiObject)) + } + + fmt.Printf("[DEBUG] flattenTargets - tfList: %#v\n", tfList) + return tfList +} + +func flattenTarget(apiObject *types.TargetSummary) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.Id; v != nil { + tfMap["id"] = aws.ToString(v) + } + + if v := apiObject.Port; v != nil { + tfMap["port"] = aws.ToInt32(v) + } + fmt.Println(tfMap) + return tfMap +} + +// Expand function for target_groups +func expandTargets(tfList []interface{}) []types.Target { + if len(tfList) == 0 { + return nil + } + + var apiObjects []types.Target + + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + + if !ok { + fmt.Printf("Error: Type assertion failed for tfMapRaw: %v\n", tfMapRaw) + continue + } + + apiObject := expandTarget(tfMap) + + apiObjects = append(apiObjects, apiObject) + } + j, err := json.Marshal(apiObjects) + if err != nil { + log.Fatal(err) + } + fmt.Println("Returning from defaultAction:", string(j)) + return apiObjects +} + +func expandTarget(tfMap map[string]interface{}) types.Target { + apiObject := types.Target{} + if v, ok := tfMap["id"].(string); ok && v != "" { + apiObject.Id = aws.String(v) + fmt.Println(apiObject.Id) + } + + if v, ok := tfMap["port"].(int); ok && v != 0 { + apiObject.Port = aws.Int32(int32(v)) + fmt.Println(apiObject.Port) + } + + return apiObject +} diff --git a/internal/service/vpclattice/register_targets_test.go b/internal/service/vpclattice/register_targets_test.go new file mode 100644 index 000000000000..4c6729addd6b --- /dev/null +++ b/internal/service/vpclattice/register_targets_test.go @@ -0,0 +1,120 @@ +package vpclattice_test + +import ( + "context" + "errors" + "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" + "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 TestAccVPCLatticeTargets_basic(t *testing.T) { + ctx := acctest.Context(t) + var targets vpclattice.ListTargetsOutput + resourceName := "aws_vpclattice_register_targets.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: testAccTargets_basic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTargetsExists(ctx, resourceName, &targets), + // acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), + // resource.TestCheckResourceAttr(resourceName, "config.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccTargets_basic() string { + return ` +resource "aws_vpclattice_register_targets" "test" { + target_group_identifier = "tg-0fcd8d514d231b311" + + targets { + id = "i-081f98c4ef2ff21e3" + port = 80 + } +} +` +} + +func testAccCheckTargetsExists(ctx context.Context, name string, targets *vpclattice.ListTargetsOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameRegisterTargets, name, errors.New("not found")) + } + + if rs.Primary.ID == "" { + return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameRegisterTargets, name, errors.New("not set")) + } + targetGroupIdentifier := rs.Primary.Attributes["target_group_identifier"] + + conn := acctest.Provider.Meta().(*conns.AWSClient).VPCLatticeClient() + resp, err := conn.ListTargets(ctx, &vpclattice.ListTargetsInput{ + TargetGroupIdentifier: aws.String(targetGroupIdentifier), + }) + + if err != nil { + return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameRegisterTargets, rs.Primary.ID, err) + } + + *targets = *resp + + return nil + } +} + +func testAccCheckTargetsDestroy(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_register_targets" { + continue + } + + targetGroupIdentifier := rs.Primary.Attributes["target_group_identifier"] + + _, err := conn.ListTargets(ctx, &vpclattice.ListTargetsInput{ + TargetGroupIdentifier: aws.String(targetGroupIdentifier), + }) + if err != nil { + var nfe *types.ResourceNotFoundException + if errors.As(err, &nfe) { + return nil + } + return err + } + + return create.Error(names.VPCLattice, create.ErrActionCheckingDestroyed, tfvpclattice.ResNameRegisterTargets, rs.Primary.ID, errors.New("not destroyed")) + } + + return nil + } +} diff --git a/internal/service/vpclattice/service_package_gen.go b/internal/service/vpclattice/service_package_gen.go index c4d9dc57fe8c..59bcdc20a913 100644 --- a/internal/service/vpclattice/service_package_gen.go +++ b/internal/service/vpclattice/service_package_gen.go @@ -51,6 +51,11 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka IdentifierAttribute: "arn", }, }, + { + Factory: ResourceRegisterTargets, + TypeName: "aws_vpclattice_register_targets", + Name: "Register Targets", + }, { Factory: ResourceService, TypeName: "aws_vpclattice_service", diff --git a/website/docs/r/vpclattice_register_targets.html.markdown b/website/docs/r/vpclattice_register_targets.html.markdown new file mode 100644 index 000000000000..e98fd43f8be0 --- /dev/null +++ b/website/docs/r/vpclattice_register_targets.html.markdown @@ -0,0 +1,53 @@ +--- +subcategory: "VPC Lattice" +layout: "aws" +page_title: "AWS: aws_vpclattice_register_targets" +description: |- + Terraform resource for managing an AWS VPC Lattice Register Targets. +--- + +# Resource: aws_vpclattice_register_targets + +Terraform resource for managing an AWS VPC Lattice Register Targets. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_vpclattice_register_targets" "example" { +} +``` + +## Argument Reference + +The following arguments are required: + +* `example_arg` - (Required) Concise argument description. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. + +The following arguments are optional: + +* `optional_arg` - (Optional) Concise argument description. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - ARN of the Register Targets. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. +* `example_attribute` - Concise description. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. + +## Timeouts + +[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): + +* `create` - (Default `60m`) +* `update` - (Default `180m`) +* `delete` - (Default `90m`) + +## Import + +VPC Lattice Register Targets can be imported using the `example_id_arg`, e.g., + +``` +$ terraform import aws_vpclattice_register_targets.example rft-8012925589 +``` From a12a38618224c97b0906bd3b0c4813dc59339fe9 Mon Sep 17 00:00:00 2001 From: Markos Kandylis Date: Tue, 25 Apr 2023 11:49:09 +0100 Subject: [PATCH 02/17] adding waiters --- .../service/vpclattice/register_targets.go | 154 ++++++++++++++++-- .../vpclattice/register_targets_test.go | 2 +- 2 files changed, 140 insertions(+), 16 deletions(-) diff --git a/internal/service/vpclattice/register_targets.go b/internal/service/vpclattice/register_targets.go index 1a2ae6f551a5..ed6a00696853 100644 --- a/internal/service/vpclattice/register_targets.go +++ b/internal/service/vpclattice/register_targets.go @@ -18,6 +18,7 @@ import ( "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" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -31,8 +32,15 @@ func ResourceRegisterTargets() *schema.Resource { UpdateWithoutTimeout: resourceRegisterTargetsUpdate, DeleteWithoutTimeout: resourceRegisterTargetsDelete, + // Importer: &schema.ResourceImporter{ + // StateContext: schema.ImportStatePassthroughContext, + // }, Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, + StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + d.Set("target_group_identifier", d.Id()) + + return []*schema.ResourceData{d}, nil + }, }, Timeouts: &schema.ResourceTimeout{ @@ -81,6 +89,9 @@ func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, in.Targets = expandTargets(v.([]interface{})) } + log.Printf("[INFO] Registering Target with Target Group %s", + d.Get("target_group_identifier").(string)) + out, err := conn.RegisterTargets(ctx, in) if err != nil { return create.DiagError(names.VPCLattice, create.ErrActionCreating, ResNameRegisterTargets, "id", err) @@ -91,19 +102,19 @@ func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, } d.SetId(aws.ToString(in.TargetGroupIdentifier)) - // d.SetId(id.PrefixedUniqueId(fmt.Sprintf("%s-", d.Get("target_group_identifier")))) + + if _, err := waitRegisterTargets(ctx, conn, d.Id(), out, d.Timeout(schema.TimeoutCreate)); err != nil { + return create.DiagError(names.VPCLattice, create.ErrActionWaitingForCreation, ResNameRegisterTargets, d.Id(), err) + } return resourceRegisterTargetsRead(ctx, d, meta) } func resourceRegisterTargetsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - fmt.Println("I am at read") conn := meta.(*conns.AWSClient).VPCLatticeClient() targetGroupIdentifier := d.Get("target_group_identifier").(string) - fmt.Println(targetGroupIdentifier) out, err := findRegisterTargets(ctx, conn, targetGroupIdentifier) - fmt.Println(d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] VpcLattice RegisterTargets (%s) not found, removing from state", d.Id()) d.SetId("") @@ -125,6 +136,37 @@ func resourceRegisterTargetsRead(ctx context.Context, d *schema.ResourceData, me } func resourceRegisterTargetsUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + if d.HasChange("targets") { + conn := meta.(*conns.AWSClient).VPCLatticeClient() + + targetGroupIdentifier := d.Get("target_group_identifier").(string) + + // Deregister old targets + oldTargetsRaw, _ := d.GetChange("targets") + oldTargets := expandTargets(oldTargetsRaw.([]interface{})) + + _, err := conn.DeregisterTargets(ctx, &vpclattice.DeregisterTargetsInput{ + TargetGroupIdentifier: aws.String(targetGroupIdentifier), + Targets: oldTargets, + }) + + if err != nil { + return diag.FromErr(fmt.Errorf("error deregistering old targets: %s", err)) + } + + // Register new targets + newTargetsRaw := d.Get("targets") + newTargets := expandTargets(newTargetsRaw.([]interface{})) + + _, err = conn.RegisterTargets(ctx, &vpclattice.RegisterTargetsInput{ + TargetGroupIdentifier: aws.String(targetGroupIdentifier), + Targets: newTargets, + }) + + if err != nil { + return diag.FromErr(fmt.Errorf("error registering new targets: %s", err)) + } + } return resourceRegisterTargetsRead(ctx, d, meta) } @@ -138,7 +180,7 @@ func resourceRegisterTargetsDelete(ctx context.Context, d *schema.ResourceData, targetsRaw := d.Get("targets").([]interface{}) targets := expandTargets(targetsRaw) - _, err := conn.DeregisterTargets(ctx, &vpclattice.DeregisterTargetsInput{ + out, err := conn.DeregisterTargets(ctx, &vpclattice.DeregisterTargetsInput{ TargetGroupIdentifier: aws.String(targetGroupIdentifier), Targets: targets, }) @@ -152,11 +194,14 @@ func resourceRegisterTargetsDelete(ctx context.Context, d *schema.ResourceData, return create.DiagError(names.VPCLattice, create.ErrActionDeleting, ResNameRegisterTargets, d.Id(), err) } + if _, err := waitDeleteTargets(ctx, conn, d.Id(), out, d.Timeout(schema.TimeoutDelete)); err != nil { + return create.DiagError(names.VPCLattice, create.ErrActionWaitingForDeletion, ResNameTargetGroup, d.Id(), err) + } + return nil } func findRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string) (*vpclattice.ListTargetsOutput, error) { - fmt.Println("I am at find") in := &vpclattice.ListTargetsInput{ TargetGroupIdentifier: aws.String(id), } @@ -176,10 +221,94 @@ func findRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string if out == nil || out.Items == nil { return nil, tfresource.NewEmptyResultError(in) } + j, err := json.Marshal(out) + if err != nil { + log.Fatal(err) + } + fmt.Println("Returning from Find Targets:", string(j)) + return out, nil +} + +func waitRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string, out *vpclattice.RegisterTargetsOutput, timeout time.Duration) (*vpclattice.RegisterTargetsOutput, error) { + var lastErr error + + for _, target := range out.Successful { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice(types.TargetStatusInitial), + Target: enum.Slice(types.TargetStatusHealthy, types.TargetStatusUnhealthy), + Refresh: statusTarget(ctx, conn, id, target), + Timeout: timeout, + NotFoundChecks: 20, + ContinuousTargetOccurence: 2, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if err != nil { + lastErr = err + continue + } + + if out, ok := outputRaw.(*vpclattice.RegisterTargetsOutput); ok { + out.Successful = append(out.Successful, target) + } + } + + if lastErr != nil { + return nil, lastErr + } + + return out, nil +} + +func waitDeleteTargets(ctx context.Context, conn *vpclattice.Client, id string, out *vpclattice.DeregisterTargetsOutput, timeout time.Duration) (*vpclattice.DeregisterTargetsOutput, error) { + var lastErr error + + for _, target := range out.Successful { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice(types.TargetStatusDraining, types.TargetStatusHealthy, types.TargetStatusUnhealthy), + Target: []string{}, + Refresh: statusTarget(ctx, conn, id, target), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if err != nil { + lastErr = err + continue + } + + if out, ok := outputRaw.(*vpclattice.RegisterTargetsOutput); ok { + out.Successful = append(out.Successful, target) + } + } + + if lastErr != nil { + return nil, lastErr + } return out, nil } +func statusTarget(ctx context.Context, conn *vpclattice.Client, id string, target types.Target) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + in := &vpclattice.ListTargetsInput{ + TargetGroupIdentifier: aws.String(id), + } + out, err := conn.ListTargets(ctx, in) + if err != nil { + return nil, "", err + } + + for _, targetSummary := range out.Items { + if aws.ToString(targetSummary.Id) == aws.ToString(target.Id) && (target.Port == nil || aws.ToInt32(targetSummary.Port) == aws.ToInt32(target.Port)) { + return targetSummary, string(targetSummary.Status), nil + } + } + + return nil, "", &retry.NotFoundError{LastError: err, LastRequest: in} + } +} + func flattenTargets(apiObjects []types.TargetSummary) []interface{} { if len(apiObjects) == 0 { return nil @@ -188,11 +317,9 @@ func flattenTargets(apiObjects []types.TargetSummary) []interface{} { var tfList []interface{} for _, apiObject := range apiObjects { - fmt.Printf("[DEBUG] flattenTargets - apiObject: %#v\n", apiObject) tfList = append(tfList, flattenTarget(&apiObject)) } - fmt.Printf("[DEBUG] flattenTargets - tfList: %#v\n", tfList) return tfList } @@ -210,7 +337,7 @@ func flattenTarget(apiObject *types.TargetSummary) map[string]interface{} { if v := apiObject.Port; v != nil { tfMap["port"] = aws.ToInt32(v) } - fmt.Println(tfMap) + return tfMap } @@ -234,16 +361,13 @@ func expandTargets(tfList []interface{}) []types.Target { apiObjects = append(apiObjects, apiObject) } - j, err := json.Marshal(apiObjects) - if err != nil { - log.Fatal(err) - } - fmt.Println("Returning from defaultAction:", string(j)) + return apiObjects } func expandTarget(tfMap map[string]interface{}) types.Target { apiObject := types.Target{} + if v, ok := tfMap["id"].(string); ok && v != "" { apiObject.Id = aws.String(v) fmt.Println(apiObject.Id) diff --git a/internal/service/vpclattice/register_targets_test.go b/internal/service/vpclattice/register_targets_test.go index 4c6729addd6b..6abde44d4e2e 100644 --- a/internal/service/vpclattice/register_targets_test.go +++ b/internal/service/vpclattice/register_targets_test.go @@ -53,7 +53,7 @@ func TestAccVPCLatticeTargets_basic(t *testing.T) { func testAccTargets_basic() string { return ` resource "aws_vpclattice_register_targets" "test" { - target_group_identifier = "tg-0fcd8d514d231b311" + target_group_identifier = "tg-00153386728e69d10" targets { id = "i-081f98c4ef2ff21e3" From bfc8cab3be7fb543eb57e229c04cca9eb21987fe Mon Sep 17 00:00:00 2001 From: markos kandylis Date: Wed, 26 Apr 2023 16:56:16 +0100 Subject: [PATCH 03/17] Creating a list of targets --- .../service/vpclattice/register_targets.go | 274 ++++++++++++++++-- .../vpclattice/register_targets_test.go | 2 +- 2 files changed, 246 insertions(+), 30 deletions(-) diff --git a/internal/service/vpclattice/register_targets.go b/internal/service/vpclattice/register_targets.go index ed6a00696853..8126ca2f2083 100644 --- a/internal/service/vpclattice/register_targets.go +++ b/internal/service/vpclattice/register_targets.go @@ -6,13 +6,13 @@ import ( "errors" "fmt" "log" + "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/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -37,8 +37,10 @@ func ResourceRegisterTargets() *schema.Resource { // }, Importer: &schema.ResourceImporter{ StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - d.Set("target_group_identifier", d.Id()) - + idParts := strings.Split(d.Id(), "/") + serviceIdentifier := idParts[0] + d.Set("target_group_identifier", serviceIdentifier) + fmt.Println(idParts) return []*schema.ResourceData{d}, nil }, }, @@ -61,13 +63,57 @@ func ResourceRegisterTargets() *schema.Resource { Schema: map[string]*schema.Schema{ "id": { Type: schema.TypeString, - Required: true, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 2048), + }, + "port": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + "successful": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 2048), + }, + "port": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + "unsuccessful": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, ValidateFunc: validation.StringLenBetween(1, 2048), }, "port": { Type: schema.TypeInt, Optional: true, }, + "failure_code": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 2048), + }, + "failure_message": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 2048), + }, }, }, }, @@ -86,24 +132,36 @@ func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, } if v, ok := d.GetOk("targets"); ok && len(v.([]interface{})) > 0 && v.([]interface{}) != nil { - in.Targets = expandTargets(v.([]interface{})) + targets := expandTargets(v.([]interface{})) + for _, target := range targets { + log.Printf("[INFO] Registering Target %s with Target Group %s", aws.ToString(target.Id), d.Get("target_group_identifier").(string)) + } + in.Targets = targets } - log.Printf("[INFO] Registering Target with Target Group %s", - d.Get("target_group_identifier").(string)) - out, err := conn.RegisterTargets(ctx, in) if err != nil { - return create.DiagError(names.VPCLattice, create.ErrActionCreating, ResNameRegisterTargets, "id", err) + return create.DiagError(names.VPCLattice, create.ErrActionCreating, ResNameRegisterTargets, d.Get("target_group_identifier").(string), err) } if out == nil { - return create.DiagError(names.VPCLattice, create.ErrActionCreating, ResNameRegisterTargets, "id", errors.New("empty output")) + return create.DiagError(names.VPCLattice, create.ErrActionCreating, ResNameRegisterTargets, d.Get("target_group_identifier").(string), errors.New("empty output")) } - d.SetId(aws.ToString(in.TargetGroupIdentifier)) + d.Set("successful", flattenTargetsSuccessful(out.Successful)) + d.Set("unsuccessful", flattenTargetsUnSuccessful(out.Unsuccessful)) + + parts := []string{ + d.Get("target_group_identifier").(string), + } - if _, err := waitRegisterTargets(ctx, conn, d.Id(), out, d.Timeout(schema.TimeoutCreate)); err != nil { + for _, target := range out.Successful { + parts = append(parts, *target.Id) + } + + d.SetId(strings.Join(parts, "/")) + + if _, err := waitRegisterTargets(ctx, conn, d.Get("target_group_identifier").(string), out, d.Timeout(schema.TimeoutCreate)); err != nil { return create.DiagError(names.VPCLattice, create.ErrActionWaitingForCreation, ResNameRegisterTargets, d.Id(), err) } @@ -113,8 +171,16 @@ func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, func resourceRegisterTargetsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).VPCLatticeClient() - targetGroupIdentifier := d.Get("target_group_identifier").(string) - out, err := findRegisterTargets(ctx, conn, targetGroupIdentifier) + targetGroupId := d.Get("target_group_identifier").(string) + targets := d.Get("targets").([]interface{}) + success := d.Get("successful").([]interface{}) + j, err := json.Marshal(success) + if err != nil { + log.Fatal(err) + } + fmt.Println("Returning from Wait Was Succ poppulated?:", string(j)) + out, err := findRegisterTargets(ctx, conn, targetGroupId, targets) + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] VpcLattice RegisterTargets (%s) not found, removing from state", d.Id()) d.SetId("") @@ -125,9 +191,6 @@ func resourceRegisterTargetsRead(ctx context.Context, d *schema.ResourceData, me return create.DiagError(names.VPCLattice, create.ErrActionReading, ResNameRegisterTargets, d.Id(), err) } - // if err := d.Set("targets", []interface{}{flattenTargets(out.Items)}); err != nil { - // return create.DiagError(names.VPCLattice, create.ErrActionSetting, ResNameRegisterTargets, d.Id(), err) - // } if err := d.Set("targets", flattenTargets(out.Items)); err != nil { return diag.FromErr(fmt.Errorf("error setting targets: %s", err)) } @@ -175,7 +238,6 @@ func resourceRegisterTargetsDelete(ctx context.Context, d *schema.ResourceData, conn := meta.(*conns.AWSClient).VPCLatticeClient() - log.Printf("[INFO] Deleting VpcLattice RegisterTargets %s", d.Id()) targetGroupIdentifier := d.Get("target_group_identifier").(string) targetsRaw := d.Get("targets").([]interface{}) targets := expandTargets(targetsRaw) @@ -194,16 +256,17 @@ func resourceRegisterTargetsDelete(ctx context.Context, d *schema.ResourceData, return create.DiagError(names.VPCLattice, create.ErrActionDeleting, ResNameRegisterTargets, d.Id(), err) } - if _, err := waitDeleteTargets(ctx, conn, d.Id(), out, d.Timeout(schema.TimeoutDelete)); err != nil { - return create.DiagError(names.VPCLattice, create.ErrActionWaitingForDeletion, ResNameTargetGroup, d.Id(), err) + if _, err := waitDeleteTargets(ctx, conn, targetGroupIdentifier, out, d.Timeout(schema.TimeoutDelete)); err != nil { + return create.DiagError(names.VPCLattice, create.ErrActionWaitingForDeletion, ResNameRegisterTargets, d.Id(), err) } return nil } -func findRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string) (*vpclattice.ListTargetsOutput, error) { +func findRegisterTargets(ctx context.Context, conn *vpclattice.Client, targetGroupId string, targets []interface{}) (*vpclattice.ListTargetsOutput, error) { in := &vpclattice.ListTargetsInput{ - TargetGroupIdentifier: aws.String(id), + TargetGroupIdentifier: aws.String(targetGroupId), + Targets: expandTargets(targets), } out, err := conn.ListTargets(ctx, in) if err != nil { @@ -225,7 +288,7 @@ func findRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string if err != nil { log.Fatal(err) } - fmt.Println("Returning from Find Targets:", string(j)) + fmt.Println("Returning from Find targets:", string(j)) return out, nil } @@ -233,6 +296,7 @@ func waitRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string var lastErr error for _, target := range out.Successful { + log.Printf("[INFO] Registering Target %s with Target Group %s", *target.Id, id) stateConf := &retry.StateChangeConf{ Pending: enum.Slice(types.TargetStatusInitial), Target: enum.Slice(types.TargetStatusHealthy, types.TargetStatusUnhealthy), @@ -260,16 +324,21 @@ func waitRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string return out, nil } -func waitDeleteTargets(ctx context.Context, conn *vpclattice.Client, id string, out *vpclattice.DeregisterTargetsOutput, timeout time.Duration) (*vpclattice.DeregisterTargetsOutput, error) { +func waitDeleteTargets(ctx context.Context, conn *vpclattice.Client, id string, out *vpclattice.DeregisterTargetsInput, timeout time.Duration) (*vpclattice.DeregisterTargetsOutput, error) { var lastErr error - for _, target := range out.Successful { + log.Printf("[INFO] Deleting Target %s with Target Group %s", *target.Id, id) stateConf := &retry.StateChangeConf{ - Pending: enum.Slice(types.TargetStatusDraining, types.TargetStatusHealthy, types.TargetStatusUnhealthy), + Pending: enum.Slice(types.TargetStatusDraining), Target: []string{}, Refresh: statusTarget(ctx, conn, id, target), Timeout: timeout, } + j, err := json.Marshal(target) + if err != nil { + log.Fatal(err) + } + fmt.Println("Returning from Wait Delete in loop:", string(j)) outputRaw, err := stateConf.WaitForStateContext(ctx) if err != nil { @@ -309,6 +378,76 @@ func statusTarget(ctx context.Context, conn *vpclattice.Client, id string, targe } } +func flattenTargetsUnSuccessful(apiObjects []types.TargetFailure) []interface{} { + if len(apiObjects) == 0 { + return nil + } + + var tfList []interface{} + + for _, apiObject := range apiObjects { + tfList = append(tfList, flattenTargetUnSuccessful(&apiObject)) + } + + return tfList +} +func flattenTargetUnSuccessful(apiObject *types.TargetFailure) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.Id; v != nil { + tfMap["id"] = aws.ToString(v) + } + + if v := apiObject.Port; v != nil { + tfMap["port"] = aws.ToInt32(v) + } + + if v := apiObject.Id; v != nil { + tfMap["failure_code"] = aws.ToString(v) + } + + if v := apiObject.Id; v != nil { + tfMap["failure_message"] = aws.ToString(v) + } + + return tfMap +} + +func flattenTargetsSuccessful(apiObjects []types.Target) []interface{} { + if len(apiObjects) == 0 { + return nil + } + + var tfList []interface{} + + for _, apiObject := range apiObjects { + tfList = append(tfList, flattenTargetSuccessful(&apiObject)) + } + + return tfList +} +func flattenTargetSuccessful(apiObject *types.Target) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.Id; v != nil { + tfMap["id"] = aws.ToString(v) + } + + if v := apiObject.Port; v != nil { + tfMap["port"] = aws.ToInt32(v) + } + + return tfMap +} + func flattenTargets(apiObjects []types.TargetSummary) []interface{} { if len(apiObjects) == 0 { return nil @@ -342,6 +481,86 @@ func flattenTarget(apiObject *types.TargetSummary) map[string]interface{} { } // Expand function for target_groups +func expandUnsuccesfulTargets(tfList []interface{}) []types.TargetFailure { + if len(tfList) == 0 { + return nil + } + + var apiObjects []types.TargetFailure + + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + + if !ok { + continue + } + + apiObject := expandUnsuccesfulTarget(tfMap) + + apiObjects = append(apiObjects, apiObject) + } + + return apiObjects +} + +func expandUnsuccesfulTarget(tfMap map[string]interface{}) types.TargetFailure { + apiObject := types.TargetFailure{} + + if v, ok := tfMap["id"].(string); ok && v != "" { + apiObject.Id = aws.String(v) + } + + if v, ok := tfMap["port"].(int); ok && v != 0 { + apiObject.Port = aws.Int32(int32(v)) + } + + if v, ok := tfMap["failure_code"].(string); ok && v != "" { + apiObject.Id = aws.String(v) + } + + if v, ok := tfMap["failure_message"].(string); ok && v != "" { + apiObject.Id = aws.String(v) + } + + return apiObject +} + +func expandTargetsSuccessfull(tfList []interface{}) []types.Target { + if len(tfList) == 0 { + return nil + } + + var apiObjects []types.Target + + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + + if !ok { + continue + } + + apiObject := expandTarget(tfMap) + + apiObjects = append(apiObjects, apiObject) + } + + return apiObjects +} + +func expandTargetSuccessful(tfMap map[string]interface{}) types.Target { + apiObject := types.Target{} + + if v, ok := tfMap["id"].(string); ok && v != "" { + apiObject.Id = aws.String(v) + } + + if v, ok := tfMap["port"].(int); ok && v != 0 { + apiObject.Port = aws.Int32(int32(v)) + } + + return apiObject +} + func expandTargets(tfList []interface{}) []types.Target { if len(tfList) == 0 { return nil @@ -353,7 +572,6 @@ func expandTargets(tfList []interface{}) []types.Target { tfMap, ok := tfMapRaw.(map[string]interface{}) if !ok { - fmt.Printf("Error: Type assertion failed for tfMapRaw: %v\n", tfMapRaw) continue } @@ -370,12 +588,10 @@ func expandTarget(tfMap map[string]interface{}) types.Target { if v, ok := tfMap["id"].(string); ok && v != "" { apiObject.Id = aws.String(v) - fmt.Println(apiObject.Id) } if v, ok := tfMap["port"].(int); ok && v != 0 { apiObject.Port = aws.Int32(int32(v)) - fmt.Println(apiObject.Port) } return apiObject diff --git a/internal/service/vpclattice/register_targets_test.go b/internal/service/vpclattice/register_targets_test.go index 6abde44d4e2e..0ac4e617d2e0 100644 --- a/internal/service/vpclattice/register_targets_test.go +++ b/internal/service/vpclattice/register_targets_test.go @@ -58,7 +58,7 @@ resource "aws_vpclattice_register_targets" "test" { targets { id = "i-081f98c4ef2ff21e3" port = 80 - } + } } ` } From 83e5424044be7c713a3974a962a10810de16d956 Mon Sep 17 00:00:00 2001 From: markos kandylis Date: Wed, 26 Apr 2023 17:26:38 +0100 Subject: [PATCH 04/17] tests --- .../service/vpclattice/register_targets.go | 99 ++++++++----------- 1 file changed, 40 insertions(+), 59 deletions(-) diff --git a/internal/service/vpclattice/register_targets.go b/internal/service/vpclattice/register_targets.go index 8126ca2f2083..7147eca26acf 100644 --- a/internal/service/vpclattice/register_targets.go +++ b/internal/service/vpclattice/register_targets.go @@ -6,13 +6,14 @@ import ( "errors" "fmt" "log" - "strings" + // "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/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -32,18 +33,17 @@ func ResourceRegisterTargets() *schema.Resource { UpdateWithoutTimeout: resourceRegisterTargetsUpdate, DeleteWithoutTimeout: resourceRegisterTargetsDelete, - // Importer: &schema.ResourceImporter{ - // StateContext: schema.ImportStatePassthroughContext, - // }, Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - idParts := strings.Split(d.Id(), "/") - serviceIdentifier := idParts[0] - d.Set("target_group_identifier", serviceIdentifier) - fmt.Println(idParts) - return []*schema.ResourceData{d}, nil - }, + StateContext: schema.ImportStatePassthroughContext, }, + // Importer: &schema.ResourceImporter{ + // StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + // idParts := strings.Split(d.Id(), "/") + // serviceIdentifier := idParts[0] + // d.Set("target_group_identifier", serviceIdentifier) + // return []*schema.ResourceData{d}, nil + // }, + // }, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(30 * time.Minute), @@ -59,6 +59,7 @@ func ResourceRegisterTargets() *schema.Resource { "targets": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "id": { @@ -133,9 +134,6 @@ func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, if v, ok := d.GetOk("targets"); ok && len(v.([]interface{})) > 0 && v.([]interface{}) != nil { targets := expandTargets(v.([]interface{})) - for _, target := range targets { - log.Printf("[INFO] Registering Target %s with Target Group %s", aws.ToString(target.Id), d.Get("target_group_identifier").(string)) - } in.Targets = targets } @@ -151,15 +149,7 @@ func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, d.Set("successful", flattenTargetsSuccessful(out.Successful)) d.Set("unsuccessful", flattenTargetsUnSuccessful(out.Unsuccessful)) - parts := []string{ - d.Get("target_group_identifier").(string), - } - - for _, target := range out.Successful { - parts = append(parts, *target.Id) - } - - d.SetId(strings.Join(parts, "/")) + d.SetId(id.PrefixedUniqueId(fmt.Sprintf("%s-", d.Get("target_group_identifier")))) if _, err := waitRegisterTargets(ctx, conn, d.Get("target_group_identifier").(string), out, d.Timeout(schema.TimeoutCreate)); err != nil { return create.DiagError(names.VPCLattice, create.ErrActionWaitingForCreation, ResNameRegisterTargets, d.Id(), err) @@ -173,12 +163,7 @@ func resourceRegisterTargetsRead(ctx context.Context, d *schema.ResourceData, me targetGroupId := d.Get("target_group_identifier").(string) targets := d.Get("targets").([]interface{}) - success := d.Get("successful").([]interface{}) - j, err := json.Marshal(success) - if err != nil { - log.Fatal(err) - } - fmt.Println("Returning from Wait Was Succ poppulated?:", string(j)) + out, err := findRegisterTargets(ctx, conn, targetGroupId, targets) if !d.IsNewResource() && tfresource.NotFound(err) { @@ -199,37 +184,37 @@ func resourceRegisterTargetsRead(ctx context.Context, d *schema.ResourceData, me } func resourceRegisterTargetsUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - if d.HasChange("targets") { - conn := meta.(*conns.AWSClient).VPCLatticeClient() + // if d.HasChange("targets") { + // conn := meta.(*conns.AWSClient).VPCLatticeClient() - targetGroupIdentifier := d.Get("target_group_identifier").(string) + // targetGroupIdentifier := d.Get("target_group_identifier").(string) - // Deregister old targets - oldTargetsRaw, _ := d.GetChange("targets") - oldTargets := expandTargets(oldTargetsRaw.([]interface{})) + // // Deregister old targets + // oldTargetsRaw, _ := d.GetChange("targets") + // oldTargets := expandTargets(oldTargetsRaw.([]interface{})) - _, err := conn.DeregisterTargets(ctx, &vpclattice.DeregisterTargetsInput{ - TargetGroupIdentifier: aws.String(targetGroupIdentifier), - Targets: oldTargets, - }) + // _, err := conn.DeregisterTargets(ctx, &vpclattice.DeregisterTargetsInput{ + // TargetGroupIdentifier: aws.String(targetGroupIdentifier), + // Targets: oldTargets, + // }) - if err != nil { - return diag.FromErr(fmt.Errorf("error deregistering old targets: %s", err)) - } + // if err != nil { + // return diag.FromErr(fmt.Errorf("error deregistering old targets: %s", err)) + // } - // Register new targets - newTargetsRaw := d.Get("targets") - newTargets := expandTargets(newTargetsRaw.([]interface{})) + // // Register new targets + // newTargetsRaw := d.Get("targets") + // newTargets := expandTargets(newTargetsRaw.([]interface{})) - _, err = conn.RegisterTargets(ctx, &vpclattice.RegisterTargetsInput{ - TargetGroupIdentifier: aws.String(targetGroupIdentifier), - Targets: newTargets, - }) + // _, err = conn.RegisterTargets(ctx, &vpclattice.RegisterTargetsInput{ + // TargetGroupIdentifier: aws.String(targetGroupIdentifier), + // Targets: newTargets, + // }) - if err != nil { - return diag.FromErr(fmt.Errorf("error registering new targets: %s", err)) - } - } + // if err != nil { + // return diag.FromErr(fmt.Errorf("error registering new targets: %s", err)) + // } + // } return resourceRegisterTargetsRead(ctx, d, meta) } @@ -284,11 +269,7 @@ func findRegisterTargets(ctx context.Context, conn *vpclattice.Client, targetGro if out == nil || out.Items == nil { return nil, tfresource.NewEmptyResultError(in) } - j, err := json.Marshal(out) - if err != nil { - log.Fatal(err) - } - fmt.Println("Returning from Find targets:", string(j)) + return out, nil } @@ -324,7 +305,7 @@ func waitRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string return out, nil } -func waitDeleteTargets(ctx context.Context, conn *vpclattice.Client, id string, out *vpclattice.DeregisterTargetsInput, timeout time.Duration) (*vpclattice.DeregisterTargetsOutput, error) { +func waitDeleteTargets(ctx context.Context, conn *vpclattice.Client, id string, out *vpclattice.DeregisterTargetsOutput, timeout time.Duration) (*vpclattice.DeregisterTargetsOutput, error) { var lastErr error for _, target := range out.Successful { log.Printf("[INFO] Deleting Target %s with Target Group %s", *target.Id, id) From f299187f1453517227e297ca32760f3175885479 Mon Sep 17 00:00:00 2001 From: markos kandylis Date: Thu, 27 Apr 2023 10:34:29 +0100 Subject: [PATCH 05/17] Adding target group identifier to the importer --- .../service/vpclattice/register_targets.go | 203 +++++++++++------- 1 file changed, 123 insertions(+), 80 deletions(-) diff --git a/internal/service/vpclattice/register_targets.go b/internal/service/vpclattice/register_targets.go index 7147eca26acf..1cafb5bdc92b 100644 --- a/internal/service/vpclattice/register_targets.go +++ b/internal/service/vpclattice/register_targets.go @@ -13,7 +13,6 @@ 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/id" "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" @@ -36,14 +35,6 @@ func ResourceRegisterTargets() *schema.Resource { Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, - // Importer: &schema.ResourceImporter{ - // StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - // idParts := strings.Split(d.Id(), "/") - // serviceIdentifier := idParts[0] - // d.Set("target_group_identifier", serviceIdentifier) - // return []*schema.ResourceData{d}, nil - // }, - // }, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(30 * time.Minute), @@ -59,7 +50,6 @@ func ResourceRegisterTargets() *schema.Resource { "targets": { Type: schema.TypeList, Optional: true, - MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "id": { @@ -128,12 +118,16 @@ const ( func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).VPCLatticeClient() + in := &vpclattice.RegisterTargetsInput{ TargetGroupIdentifier: aws.String(d.Get("target_group_identifier").(string)), } if v, ok := d.GetOk("targets"); ok && len(v.([]interface{})) > 0 && v.([]interface{}) != nil { targets := expandTargets(v.([]interface{})) + for _, target := range targets { + log.Printf("[INFO] Registering Target %s with Target Group %s", aws.ToString(target.Id), d.Get("target_group_identifier").(string)) + } in.Targets = targets } @@ -149,9 +143,13 @@ func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, d.Set("successful", flattenTargetsSuccessful(out.Successful)) d.Set("unsuccessful", flattenTargetsUnSuccessful(out.Unsuccessful)) - d.SetId(id.PrefixedUniqueId(fmt.Sprintf("%s-", d.Get("target_group_identifier")))) - if _, err := waitRegisterTargets(ctx, conn, d.Get("target_group_identifier").(string), out, d.Timeout(schema.TimeoutCreate)); err != nil { + d.SetId(aws.ToString(in.TargetGroupIdentifier)) + + targetGroupIdentifier := d.Get("target_group_identifier").(string) + targets := d.Get("targets").([]interface{}) + + if _, err := waitRegisterTargets(ctx, conn, targetGroupIdentifier, targets, d.Timeout(schema.TimeoutCreate)); err != nil { return create.DiagError(names.VPCLattice, create.ErrActionWaitingForCreation, ResNameRegisterTargets, d.Id(), err) } @@ -227,7 +225,7 @@ func resourceRegisterTargetsDelete(ctx context.Context, d *schema.ResourceData, targetsRaw := d.Get("targets").([]interface{}) targets := expandTargets(targetsRaw) - out, err := conn.DeregisterTargets(ctx, &vpclattice.DeregisterTargetsInput{ + _, err := conn.DeregisterTargets(ctx, &vpclattice.DeregisterTargetsInput{ TargetGroupIdentifier: aws.String(targetGroupIdentifier), Targets: targets, }) @@ -240,8 +238,8 @@ func resourceRegisterTargetsDelete(ctx context.Context, d *schema.ResourceData, return create.DiagError(names.VPCLattice, create.ErrActionDeleting, ResNameRegisterTargets, d.Id(), err) } - - if _, err := waitDeleteTargets(ctx, conn, targetGroupIdentifier, out, d.Timeout(schema.TimeoutDelete)); err != nil { + + if _, err := waitDeleteTargets(ctx, conn, targetGroupIdentifier, targetsRaw, d.Timeout(schema.TimeoutDelete)); err != nil { return create.DiagError(names.VPCLattice, create.ErrActionWaitingForDeletion, ResNameRegisterTargets, d.Id(), err) } @@ -269,96 +267,141 @@ func findRegisterTargets(ctx context.Context, conn *vpclattice.Client, targetGro if out == nil || out.Items == nil { return nil, tfresource.NewEmptyResultError(in) } - + j, err := json.Marshal(out) + if err != nil { + log.Fatal(err) + } + fmt.Println("Returning from Find targets:", string(j)) return out, nil } -func waitRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string, out *vpclattice.RegisterTargetsOutput, timeout time.Duration) (*vpclattice.RegisterTargetsOutput, error) { - var lastErr error - - for _, target := range out.Successful { - log.Printf("[INFO] Registering Target %s with Target Group %s", *target.Id, id) - stateConf := &retry.StateChangeConf{ - Pending: enum.Slice(types.TargetStatusInitial), - Target: enum.Slice(types.TargetStatusHealthy, types.TargetStatusUnhealthy), - Refresh: statusTarget(ctx, conn, id, target), - Timeout: timeout, - NotFoundChecks: 20, - ContinuousTargetOccurence: 2, - } - - outputRaw, err := stateConf.WaitForStateContext(ctx) - if err != nil { - lastErr = err - continue - } - - if out, ok := outputRaw.(*vpclattice.RegisterTargetsOutput); ok { - out.Successful = append(out.Successful, target) - } +func waitRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string, targets []interface{}, timeout time.Duration) (*vpclattice.RegisterTargetsOutput, error) { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice(types.TargetStatusInitial), + Target: enum.Slice(types.TargetStatusHealthy, types.TargetStatusUnhealthy), + Refresh: statusTarget(ctx, conn, id, targets), + Timeout: timeout, + NotFoundChecks: 20, + ContinuousTargetOccurence: 2, } - if lastErr != nil { - return nil, lastErr + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*vpclattice.RegisterTargetsOutput); ok { + return out, err } - return out, nil + return nil, err } -func waitDeleteTargets(ctx context.Context, conn *vpclattice.Client, id string, out *vpclattice.DeregisterTargetsOutput, timeout time.Duration) (*vpclattice.DeregisterTargetsOutput, error) { - var lastErr error - for _, target := range out.Successful { - log.Printf("[INFO] Deleting Target %s with Target Group %s", *target.Id, id) - stateConf := &retry.StateChangeConf{ - Pending: enum.Slice(types.TargetStatusDraining), - Target: []string{}, - Refresh: statusTarget(ctx, conn, id, target), - Timeout: timeout, - } - j, err := json.Marshal(target) - if err != nil { - log.Fatal(err) - } - fmt.Println("Returning from Wait Delete in loop:", string(j)) - - outputRaw, err := stateConf.WaitForStateContext(ctx) - if err != nil { - lastErr = err - continue - } - - if out, ok := outputRaw.(*vpclattice.RegisterTargetsOutput); ok { - out.Successful = append(out.Successful, target) - } +func waitDeleteTargets(ctx context.Context, conn *vpclattice.Client, id string, targets []interface{}, timeout time.Duration) (*vpclattice.DeregisterTargetsOutput, error) { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice(types.TargetStatusDraining), + Target: []string{}, + Refresh: statusTarget(ctx, conn, id, targets), + Timeout: timeout, } - if lastErr != nil { - return nil, lastErr + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*vpclattice.DeregisterTargetsOutput); ok { + return out, err } - return out, nil + return nil, err } -func statusTarget(ctx context.Context, conn *vpclattice.Client, id string, target types.Target) retry.StateRefreshFunc { +func statusTarget(ctx context.Context, conn *vpclattice.Client, id string, targets []interface{}) retry.StateRefreshFunc { return func() (interface{}, string, error) { - in := &vpclattice.ListTargetsInput{ - TargetGroupIdentifier: aws.String(id), + out, err := findRegisterTargets(ctx, conn, id, targets) + if tfresource.NotFound(err) { + return nil, "", nil } - out, err := conn.ListTargets(ctx, in) + if err != nil { return nil, "", err } - for _, targetSummary := range out.Items { - if aws.ToString(targetSummary.Id) == aws.ToString(target.Id) && (target.Port == nil || aws.ToInt32(targetSummary.Port) == aws.ToInt32(target.Port)) { - return targetSummary, string(targetSummary.Status), nil - } - } + status := out.Items[0].Status - return nil, "", &retry.NotFoundError{LastError: err, LastRequest: in} + return out, string(status), nil } } +// func statusTarget(ctx context.Context, conn *vpclattice.Client, id string, target types.Target) retry.StateRefreshFunc { +// return func() (interface{}, string, error) { +// in := &vpclattice.ListTargetsInput{ +// TargetGroupIdentifier: aws.String(id), +// } +// out, err := conn.ListTargets(ctx, in) +// if err != nil { +// return nil, "", err +// } + +// for _, targetSummary := range out.Items { +// if aws.ToString(targetSummary.Id) == aws.ToString(target.Id) && (target.Port == nil || aws.ToInt32(targetSummary.Port) == aws.ToInt32(target.Port)) { +// return targetSummary, string(targetSummary.Status), nil +// } +// } + +// return nil, "", &retry.NotFoundError{LastError: err, LastRequest: in} +// } +// } + +// func waitRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string, out *vpclattice.RegisterTargetsOutput, timeout time.Duration) (*vpclattice.RegisterTargetsOutput, error) { +// var lastErr error + +// for _, target := range out.Successful { +// log.Printf("[INFO] Registering Target %s with Target Group %s", *target.Id, id) +// stateConf := &retry.StateChangeConf{ +// Pending: enum.Slice(types.TargetStatusInitial), +// Target: enum.Slice(types.TargetStatusHealthy, types.TargetStatusUnhealthy), +// Refresh: statusTarget(ctx, conn, id, target), +// Timeout: timeout, +// NotFoundChecks: 20, +// ContinuousTargetOccurence: 2, +// } + +// outputRaw, err := stateConf.WaitForStateContext(ctx) +// if err != nil { +// lastErr = err +// continue +// } + +// if out, ok := outputRaw.(*vpclattice.RegisterTargetsOutput); ok { +// out.Successful = append(out.Successful, target) +// } +// } + +// if lastErr != nil { +// return nil, lastErr +// } + +// return out, nil +// } + +// func waitDeleteTargets(ctx context.Context, conn *vpclattice.Client, id string, out *vpclattice.DeregisterTargetsInput, timeout time.Duration) (*vpclattice.DeregisterTargetsOutput, error) { +// var lastErr error +// for _, target := range out.Targets { +// log.Printf("[INFO] Deleting Target %s with Target Group %s", *target.Id, id) +// stateConf := &retry.StateChangeConf{ +// Pending: enum.Slice(types.TargetStatusDraining), +// Target: []string{}, +// Refresh: statusTarget(ctx, conn, id, target), +// Timeout: timeout, +// } + +// outputRaw, err := stateConf.WaitForStateContext(ctx) +// if out, ok := outputRaw.(*vpclattice.DeregisterTargetsOutput); ok { +// out.Successful = append(out.Successful, target) +// return out, err +// } +// } + +// if lastErr != nil { +// return nil, lastErr +// } + +// } + func flattenTargetsUnSuccessful(apiObjects []types.TargetFailure) []interface{} { if len(apiObjects) == 0 { return nil From 67c24bcb9727fdec78f9b8051ee69d31b1bee215 Mon Sep 17 00:00:00 2001 From: markos kandylis Date: Thu, 27 Apr 2023 15:51:53 +0100 Subject: [PATCH 06/17] adding update --- .../service/vpclattice/register_targets.go | 225 +++++++----------- .../vpclattice/register_targets_test.go | 1 + 2 files changed, 93 insertions(+), 133 deletions(-) diff --git a/internal/service/vpclattice/register_targets.go b/internal/service/vpclattice/register_targets.go index 1cafb5bdc92b..5d193ee73bd5 100644 --- a/internal/service/vpclattice/register_targets.go +++ b/internal/service/vpclattice/register_targets.go @@ -6,13 +6,14 @@ import ( "errors" "fmt" "log" - // "strings" + "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/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -32,8 +33,18 @@ func ResourceRegisterTargets() *schema.Resource { UpdateWithoutTimeout: resourceRegisterTargetsUpdate, DeleteWithoutTimeout: resourceRegisterTargetsDelete, + // Importer: &schema.ResourceImporter{ + // StateContext: schema.ImportStatePassthroughContext, + // }, + Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, + StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + idParts := strings.Split(d.Id(), "/") + fmt.Println(idParts) + d.Set("target_group_identifier", idParts[0]) + + return []*schema.ResourceData{d}, nil + }, }, Timeouts: &schema.ResourceTimeout{ @@ -50,6 +61,8 @@ func ResourceRegisterTargets() *schema.Resource { "targets": { Type: schema.TypeList, Optional: true, + MaxItems: 1, + MinItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "id": { @@ -64,50 +77,50 @@ func ResourceRegisterTargets() *schema.Resource { }, }, }, - "successful": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 2048), - }, - "port": { - Type: schema.TypeInt, - Optional: true, - }, - }, - }, - }, - "unsuccessful": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 2048), - }, - "port": { - Type: schema.TypeInt, - Optional: true, - }, - "failure_code": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 2048), - }, - "failure_message": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 2048), - }, - }, - }, - }, + // "successful": { + // Type: schema.TypeList, + // Computed: true, + // Elem: &schema.Resource{ + // Schema: map[string]*schema.Schema{ + // "id": { + // Type: schema.TypeString, + // Optional: true, + // ValidateFunc: validation.StringLenBetween(1, 2048), + // }, + // "port": { + // Type: schema.TypeInt, + // Optional: true, + // }, + // }, + // }, + // }, + // "unsuccessful": { + // Type: schema.TypeList, + // Computed: true, + // Elem: &schema.Resource{ + // Schema: map[string]*schema.Schema{ + // "id": { + // Type: schema.TypeString, + // Optional: true, + // ValidateFunc: validation.StringLenBetween(1, 2048), + // }, + // "port": { + // Type: schema.TypeInt, + // Optional: true, + // }, + // "failure_code": { + // Type: schema.TypeString, + // Optional: true, + // ValidateFunc: validation.StringLenBetween(1, 2048), + // }, + // "failure_message": { + // Type: schema.TypeString, + // Optional: true, + // ValidateFunc: validation.StringLenBetween(1, 2048), + // }, + // }, + // }, + // }, }, } } @@ -123,10 +136,13 @@ func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, TargetGroupIdentifier: aws.String(d.Get("target_group_identifier").(string)), } + var targetId string if v, ok := d.GetOk("targets"); ok && len(v.([]interface{})) > 0 && v.([]interface{}) != nil { targets := expandTargets(v.([]interface{})) + for _, target := range targets { log.Printf("[INFO] Registering Target %s with Target Group %s", aws.ToString(target.Id), d.Get("target_group_identifier").(string)) + targetId = *target.Id } in.Targets = targets } @@ -140,15 +156,18 @@ func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, return create.DiagError(names.VPCLattice, create.ErrActionCreating, ResNameRegisterTargets, d.Get("target_group_identifier").(string), errors.New("empty output")) } - d.Set("successful", flattenTargetsSuccessful(out.Successful)) - d.Set("unsuccessful", flattenTargetsUnSuccessful(out.Unsuccessful)) - - - d.SetId(aws.ToString(in.TargetGroupIdentifier)) - targetGroupIdentifier := d.Get("target_group_identifier").(string) targets := d.Get("targets").([]interface{}) + parts := []string{ + d.Get("target_group_identifier").(string), + targetId, + } + fmt.Println(parts) + d.SetId(strings.Join(parts, "/")) + // d.SetId(id.PrefixedUniqueId(fmt.Sprintf("%s/", d.Get("target_group_arn")))) + // d.SetId(aws.ToString(in.TargetGroupIdentifier)) + if _, err := waitRegisterTargets(ctx, conn, targetGroupIdentifier, targets, d.Timeout(schema.TimeoutCreate)); err != nil { return create.DiagError(names.VPCLattice, create.ErrActionWaitingForCreation, ResNameRegisterTargets, d.Id(), err) } @@ -157,6 +176,7 @@ func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, } func resourceRegisterTargetsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + fmt.Println("Running on Read") conn := meta.(*conns.AWSClient).VPCLatticeClient() targetGroupId := d.Get("target_group_identifier").(string) @@ -238,7 +258,7 @@ func resourceRegisterTargetsDelete(ctx context.Context, d *schema.ResourceData, return create.DiagError(names.VPCLattice, create.ErrActionDeleting, ResNameRegisterTargets, d.Id(), err) } - + fmt.Println("Starting Delete Waiter") if _, err := waitDeleteTargets(ctx, conn, targetGroupIdentifier, targetsRaw, d.Timeout(schema.TimeoutDelete)); err != nil { return create.DiagError(names.VPCLattice, create.ErrActionWaitingForDeletion, ResNameRegisterTargets, d.Id(), err) } @@ -247,6 +267,7 @@ func resourceRegisterTargetsDelete(ctx context.Context, d *schema.ResourceData, } func findRegisterTargets(ctx context.Context, conn *vpclattice.Client, targetGroupId string, targets []interface{}) (*vpclattice.ListTargetsOutput, error) { + fmt.Println("Inside the Finder") in := &vpclattice.ListTargetsInput{ TargetGroupIdentifier: aws.String(targetGroupId), Targets: expandTargets(targets), @@ -271,7 +292,8 @@ func findRegisterTargets(ctx context.Context, conn *vpclattice.Client, targetGro if err != nil { log.Fatal(err) } - fmt.Println("Returning from Find targets:", string(j)) + fmt.Println("Returning from defaultAction:", string(j)) + return out, nil } @@ -294,8 +316,9 @@ func waitRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string } func waitDeleteTargets(ctx context.Context, conn *vpclattice.Client, id string, targets []interface{}, timeout time.Duration) (*vpclattice.DeregisterTargetsOutput, error) { + fmt.Println("Starting Inside Delete waiter") stateConf := &retry.StateChangeConf{ - Pending: enum.Slice(types.TargetStatusDraining), + Pending: enum.Slice(types.TargetStatusDraining, types.TargetStatusInitial), Target: []string{}, Refresh: statusTarget(ctx, conn, id, targets), Timeout: timeout, @@ -320,88 +343,24 @@ func statusTarget(ctx context.Context, conn *vpclattice.Client, id string, targe return nil, "", err } - status := out.Items[0].Status + j, err := json.Marshal(out.Items) + if err != nil { + log.Fatal(err) + } + fmt.Println("Returning from Status:", string(j)) + + var status types.TargetStatus + if len(out.Items) > 0 { + fmt.Println("Inside the len") + fmt.Println(len(out.Items)) + status = out.Items[0].Status + return out, string(status), nil + } - return out, string(status), nil + return nil, "", err } } -// func statusTarget(ctx context.Context, conn *vpclattice.Client, id string, target types.Target) retry.StateRefreshFunc { -// return func() (interface{}, string, error) { -// in := &vpclattice.ListTargetsInput{ -// TargetGroupIdentifier: aws.String(id), -// } -// out, err := conn.ListTargets(ctx, in) -// if err != nil { -// return nil, "", err -// } - -// for _, targetSummary := range out.Items { -// if aws.ToString(targetSummary.Id) == aws.ToString(target.Id) && (target.Port == nil || aws.ToInt32(targetSummary.Port) == aws.ToInt32(target.Port)) { -// return targetSummary, string(targetSummary.Status), nil -// } -// } - -// return nil, "", &retry.NotFoundError{LastError: err, LastRequest: in} -// } -// } - -// func waitRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string, out *vpclattice.RegisterTargetsOutput, timeout time.Duration) (*vpclattice.RegisterTargetsOutput, error) { -// var lastErr error - -// for _, target := range out.Successful { -// log.Printf("[INFO] Registering Target %s with Target Group %s", *target.Id, id) -// stateConf := &retry.StateChangeConf{ -// Pending: enum.Slice(types.TargetStatusInitial), -// Target: enum.Slice(types.TargetStatusHealthy, types.TargetStatusUnhealthy), -// Refresh: statusTarget(ctx, conn, id, target), -// Timeout: timeout, -// NotFoundChecks: 20, -// ContinuousTargetOccurence: 2, -// } - -// outputRaw, err := stateConf.WaitForStateContext(ctx) -// if err != nil { -// lastErr = err -// continue -// } - -// if out, ok := outputRaw.(*vpclattice.RegisterTargetsOutput); ok { -// out.Successful = append(out.Successful, target) -// } -// } - -// if lastErr != nil { -// return nil, lastErr -// } - -// return out, nil -// } - -// func waitDeleteTargets(ctx context.Context, conn *vpclattice.Client, id string, out *vpclattice.DeregisterTargetsInput, timeout time.Duration) (*vpclattice.DeregisterTargetsOutput, error) { -// var lastErr error -// for _, target := range out.Targets { -// log.Printf("[INFO] Deleting Target %s with Target Group %s", *target.Id, id) -// stateConf := &retry.StateChangeConf{ -// Pending: enum.Slice(types.TargetStatusDraining), -// Target: []string{}, -// Refresh: statusTarget(ctx, conn, id, target), -// Timeout: timeout, -// } - -// outputRaw, err := stateConf.WaitForStateContext(ctx) -// if out, ok := outputRaw.(*vpclattice.DeregisterTargetsOutput); ok { -// out.Successful = append(out.Successful, target) -// return out, err -// } -// } - -// if lastErr != nil { -// return nil, lastErr -// } - -// } - func flattenTargetsUnSuccessful(apiObjects []types.TargetFailure) []interface{} { if len(apiObjects) == 0 { return nil diff --git a/internal/service/vpclattice/register_targets_test.go b/internal/service/vpclattice/register_targets_test.go index 0ac4e617d2e0..cd5340b21763 100644 --- a/internal/service/vpclattice/register_targets_test.go +++ b/internal/service/vpclattice/register_targets_test.go @@ -103,6 +103,7 @@ func testAccCheckTargetsDestroy(ctx context.Context) resource.TestCheckFunc { _, err := conn.ListTargets(ctx, &vpclattice.ListTargetsInput{ TargetGroupIdentifier: aws.String(targetGroupIdentifier), + Targets: []types.Target{}, }) if err != nil { var nfe *types.ResourceNotFoundException From 264b62a1b4c8675f99ff98618e0096ce7fbb8359 Mon Sep 17 00:00:00 2001 From: markos kandylis Date: Fri, 28 Apr 2023 12:00:46 +0100 Subject: [PATCH 07/17] Adding lambda --- .../service/vpclattice/register_targets.go | 273 +----------------- .../vpclattice/register_targets_test.go | 2 +- 2 files changed, 16 insertions(+), 259 deletions(-) diff --git a/internal/service/vpclattice/register_targets.go b/internal/service/vpclattice/register_targets.go index 5d193ee73bd5..f1309b0461df 100644 --- a/internal/service/vpclattice/register_targets.go +++ b/internal/service/vpclattice/register_targets.go @@ -2,7 +2,7 @@ package vpclattice import ( "context" - "encoding/json" + // "encoding/json" "errors" "fmt" "log" @@ -13,7 +13,6 @@ 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/id" "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" @@ -30,13 +29,8 @@ func ResourceRegisterTargets() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceRegisterTargetsCreate, ReadWithoutTimeout: resourceRegisterTargetsRead, - UpdateWithoutTimeout: resourceRegisterTargetsUpdate, DeleteWithoutTimeout: resourceRegisterTargetsDelete, - // Importer: &schema.ResourceImporter{ - // StateContext: schema.ImportStatePassthroughContext, - // }, - Importer: &schema.ResourceImporter{ StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { idParts := strings.Split(d.Id(), "/") @@ -49,7 +43,6 @@ func ResourceRegisterTargets() *schema.Resource { Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(30 * time.Minute), - Update: schema.DefaultTimeout(30 * time.Minute), Delete: schema.DefaultTimeout(30 * time.Minute), }, @@ -57,10 +50,12 @@ func ResourceRegisterTargets() *schema.Resource { "target_group_identifier": { Type: schema.TypeString, Required: true, + ForceNew: true, }, "targets": { Type: schema.TypeList, Optional: true, + ForceNew: true, MaxItems: 1, MinItems: 1, Elem: &schema.Resource{ @@ -68,59 +63,17 @@ func ResourceRegisterTargets() *schema.Resource { "id": { Type: schema.TypeString, Optional: true, + ForceNew: true, ValidateFunc: validation.StringLenBetween(1, 2048), }, "port": { Type: schema.TypeInt, Optional: true, + ForceNew: true, }, }, }, }, - // "successful": { - // Type: schema.TypeList, - // Computed: true, - // Elem: &schema.Resource{ - // Schema: map[string]*schema.Schema{ - // "id": { - // Type: schema.TypeString, - // Optional: true, - // ValidateFunc: validation.StringLenBetween(1, 2048), - // }, - // "port": { - // Type: schema.TypeInt, - // Optional: true, - // }, - // }, - // }, - // }, - // "unsuccessful": { - // Type: schema.TypeList, - // Computed: true, - // Elem: &schema.Resource{ - // Schema: map[string]*schema.Schema{ - // "id": { - // Type: schema.TypeString, - // Optional: true, - // ValidateFunc: validation.StringLenBetween(1, 2048), - // }, - // "port": { - // Type: schema.TypeInt, - // Optional: true, - // }, - // "failure_code": { - // Type: schema.TypeString, - // Optional: true, - // ValidateFunc: validation.StringLenBetween(1, 2048), - // }, - // "failure_message": { - // Type: schema.TypeString, - // Optional: true, - // ValidateFunc: validation.StringLenBetween(1, 2048), - // }, - // }, - // }, - // }, }, } } @@ -163,10 +116,9 @@ func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, d.Get("target_group_identifier").(string), targetId, } + fmt.Println(parts) d.SetId(strings.Join(parts, "/")) - // d.SetId(id.PrefixedUniqueId(fmt.Sprintf("%s/", d.Get("target_group_arn")))) - // d.SetId(aws.ToString(in.TargetGroupIdentifier)) if _, err := waitRegisterTargets(ctx, conn, targetGroupIdentifier, targets, d.Timeout(schema.TimeoutCreate)); err != nil { return create.DiagError(names.VPCLattice, create.ErrActionWaitingForCreation, ResNameRegisterTargets, d.Id(), err) @@ -183,7 +135,8 @@ func resourceRegisterTargetsRead(ctx context.Context, d *schema.ResourceData, me targets := d.Get("targets").([]interface{}) out, err := findRegisterTargets(ctx, conn, targetGroupId, targets) - + fmt.Println("Find returns") + fmt.Println(out.Items, err) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] VpcLattice RegisterTargets (%s) not found, removing from state", d.Id()) d.SetId("") @@ -201,42 +154,6 @@ func resourceRegisterTargetsRead(ctx context.Context, d *schema.ResourceData, me return nil } -func resourceRegisterTargetsUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - // if d.HasChange("targets") { - // conn := meta.(*conns.AWSClient).VPCLatticeClient() - - // targetGroupIdentifier := d.Get("target_group_identifier").(string) - - // // Deregister old targets - // oldTargetsRaw, _ := d.GetChange("targets") - // oldTargets := expandTargets(oldTargetsRaw.([]interface{})) - - // _, err := conn.DeregisterTargets(ctx, &vpclattice.DeregisterTargetsInput{ - // TargetGroupIdentifier: aws.String(targetGroupIdentifier), - // Targets: oldTargets, - // }) - - // if err != nil { - // return diag.FromErr(fmt.Errorf("error deregistering old targets: %s", err)) - // } - - // // Register new targets - // newTargetsRaw := d.Get("targets") - // newTargets := expandTargets(newTargetsRaw.([]interface{})) - - // _, err = conn.RegisterTargets(ctx, &vpclattice.RegisterTargetsInput{ - // TargetGroupIdentifier: aws.String(targetGroupIdentifier), - // Targets: newTargets, - // }) - - // if err != nil { - // return diag.FromErr(fmt.Errorf("error registering new targets: %s", err)) - // } - // } - - return resourceRegisterTargetsRead(ctx, d, meta) -} - func resourceRegisterTargetsDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).VPCLatticeClient() @@ -258,7 +175,6 @@ func resourceRegisterTargetsDelete(ctx context.Context, d *schema.ResourceData, return create.DiagError(names.VPCLattice, create.ErrActionDeleting, ResNameRegisterTargets, d.Id(), err) } - fmt.Println("Starting Delete Waiter") if _, err := waitDeleteTargets(ctx, conn, targetGroupIdentifier, targetsRaw, d.Timeout(schema.TimeoutDelete)); err != nil { return create.DiagError(names.VPCLattice, create.ErrActionWaitingForDeletion, ResNameRegisterTargets, d.Id(), err) } @@ -285,14 +201,12 @@ func findRegisterTargets(ctx context.Context, conn *vpclattice.Client, targetGro return nil, err } - if out == nil || out.Items == nil { - return nil, tfresource.NewEmptyResultError(in) - } - j, err := json.Marshal(out) - if err != nil { - log.Fatal(err) + if len(out.Items) == 0 { + out = nil + if out == nil { + return nil, tfresource.NewEmptyResultError(in) + } } - fmt.Println("Returning from defaultAction:", string(j)) return out, nil } @@ -343,16 +257,8 @@ func statusTarget(ctx context.Context, conn *vpclattice.Client, id string, targe return nil, "", err } - j, err := json.Marshal(out.Items) - if err != nil { - log.Fatal(err) - } - fmt.Println("Returning from Status:", string(j)) - var status types.TargetStatus if len(out.Items) > 0 { - fmt.Println("Inside the len") - fmt.Println(len(out.Items)) status = out.Items[0].Status return out, string(status), nil } @@ -361,76 +267,7 @@ func statusTarget(ctx context.Context, conn *vpclattice.Client, id string, targe } } -func flattenTargetsUnSuccessful(apiObjects []types.TargetFailure) []interface{} { - if len(apiObjects) == 0 { - return nil - } - - var tfList []interface{} - - for _, apiObject := range apiObjects { - tfList = append(tfList, flattenTargetUnSuccessful(&apiObject)) - } - - return tfList -} -func flattenTargetUnSuccessful(apiObject *types.TargetFailure) map[string]interface{} { - if apiObject == nil { - return nil - } - - tfMap := map[string]interface{}{} - - if v := apiObject.Id; v != nil { - tfMap["id"] = aws.ToString(v) - } - - if v := apiObject.Port; v != nil { - tfMap["port"] = aws.ToInt32(v) - } - - if v := apiObject.Id; v != nil { - tfMap["failure_code"] = aws.ToString(v) - } - - if v := apiObject.Id; v != nil { - tfMap["failure_message"] = aws.ToString(v) - } - - return tfMap -} - -func flattenTargetsSuccessful(apiObjects []types.Target) []interface{} { - if len(apiObjects) == 0 { - return nil - } - - var tfList []interface{} - - for _, apiObject := range apiObjects { - tfList = append(tfList, flattenTargetSuccessful(&apiObject)) - } - - return tfList -} -func flattenTargetSuccessful(apiObject *types.Target) map[string]interface{} { - if apiObject == nil { - return nil - } - - tfMap := map[string]interface{}{} - - if v := apiObject.Id; v != nil { - tfMap["id"] = aws.ToString(v) - } - - if v := apiObject.Port; v != nil { - tfMap["port"] = aws.ToInt32(v) - } - - return tfMap -} - +// Flatten function for targets func flattenTargets(apiObjects []types.TargetSummary) []interface{} { if len(apiObjects) == 0 { return nil @@ -463,87 +300,7 @@ func flattenTarget(apiObject *types.TargetSummary) map[string]interface{} { return tfMap } -// Expand function for target_groups -func expandUnsuccesfulTargets(tfList []interface{}) []types.TargetFailure { - if len(tfList) == 0 { - return nil - } - - var apiObjects []types.TargetFailure - - for _, tfMapRaw := range tfList { - tfMap, ok := tfMapRaw.(map[string]interface{}) - - if !ok { - continue - } - - apiObject := expandUnsuccesfulTarget(tfMap) - - apiObjects = append(apiObjects, apiObject) - } - - return apiObjects -} - -func expandUnsuccesfulTarget(tfMap map[string]interface{}) types.TargetFailure { - apiObject := types.TargetFailure{} - - if v, ok := tfMap["id"].(string); ok && v != "" { - apiObject.Id = aws.String(v) - } - - if v, ok := tfMap["port"].(int); ok && v != 0 { - apiObject.Port = aws.Int32(int32(v)) - } - - if v, ok := tfMap["failure_code"].(string); ok && v != "" { - apiObject.Id = aws.String(v) - } - - if v, ok := tfMap["failure_message"].(string); ok && v != "" { - apiObject.Id = aws.String(v) - } - - return apiObject -} - -func expandTargetsSuccessfull(tfList []interface{}) []types.Target { - if len(tfList) == 0 { - return nil - } - - var apiObjects []types.Target - - for _, tfMapRaw := range tfList { - tfMap, ok := tfMapRaw.(map[string]interface{}) - - if !ok { - continue - } - - apiObject := expandTarget(tfMap) - - apiObjects = append(apiObjects, apiObject) - } - - return apiObjects -} - -func expandTargetSuccessful(tfMap map[string]interface{}) types.Target { - apiObject := types.Target{} - - if v, ok := tfMap["id"].(string); ok && v != "" { - apiObject.Id = aws.String(v) - } - - if v, ok := tfMap["port"].(int); ok && v != 0 { - apiObject.Port = aws.Int32(int32(v)) - } - - return apiObject -} - +// Expand function for targets func expandTargets(tfList []interface{}) []types.Target { if len(tfList) == 0 { return nil diff --git a/internal/service/vpclattice/register_targets_test.go b/internal/service/vpclattice/register_targets_test.go index cd5340b21763..b6adb4bf670a 100644 --- a/internal/service/vpclattice/register_targets_test.go +++ b/internal/service/vpclattice/register_targets_test.go @@ -56,7 +56,7 @@ resource "aws_vpclattice_register_targets" "test" { target_group_identifier = "tg-00153386728e69d10" targets { - id = "i-081f98c4ef2ff21e3" + id = "i-081f98c4ef2ff21e3x" port = 80 } } From b3f49666b12018dcaaa26eee4c0b816dc140a3f4 Mon Sep 17 00:00:00 2001 From: markos kandylis Date: Fri, 28 Apr 2023 19:48:24 +0100 Subject: [PATCH 08/17] Succeded tests --- .../service/vpclattice/register_targets.go | 11 +- .../vpclattice/register_targets_test.go | 263 ++++++++++++++++-- .../vpclattice/test-fixtures/lambda.zip | Bin 0 -> 507 bytes 3 files changed, 249 insertions(+), 25 deletions(-) create mode 100644 internal/service/vpclattice/test-fixtures/lambda.zip diff --git a/internal/service/vpclattice/register_targets.go b/internal/service/vpclattice/register_targets.go index f1309b0461df..d87a8f595482 100644 --- a/internal/service/vpclattice/register_targets.go +++ b/internal/service/vpclattice/register_targets.go @@ -2,7 +2,6 @@ package vpclattice import ( "context" - // "encoding/json" "errors" "fmt" "log" @@ -34,7 +33,6 @@ func ResourceRegisterTargets() *schema.Resource { Importer: &schema.ResourceImporter{ StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { idParts := strings.Split(d.Id(), "/") - fmt.Println(idParts) d.Set("target_group_identifier", idParts[0]) return []*schema.ResourceData{d}, nil @@ -117,7 +115,6 @@ func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, targetId, } - fmt.Println(parts) d.SetId(strings.Join(parts, "/")) if _, err := waitRegisterTargets(ctx, conn, targetGroupIdentifier, targets, d.Timeout(schema.TimeoutCreate)); err != nil { @@ -128,15 +125,13 @@ func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, } func resourceRegisterTargetsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - fmt.Println("Running on Read") conn := meta.(*conns.AWSClient).VPCLatticeClient() targetGroupId := d.Get("target_group_identifier").(string) targets := d.Get("targets").([]interface{}) out, err := findRegisterTargets(ctx, conn, targetGroupId, targets) - fmt.Println("Find returns") - fmt.Println(out.Items, err) + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] VpcLattice RegisterTargets (%s) not found, removing from state", d.Id()) d.SetId("") @@ -183,7 +178,6 @@ func resourceRegisterTargetsDelete(ctx context.Context, d *schema.ResourceData, } func findRegisterTargets(ctx context.Context, conn *vpclattice.Client, targetGroupId string, targets []interface{}) (*vpclattice.ListTargetsOutput, error) { - fmt.Println("Inside the Finder") in := &vpclattice.ListTargetsInput{ TargetGroupIdentifier: aws.String(targetGroupId), Targets: expandTargets(targets), @@ -214,7 +208,7 @@ func findRegisterTargets(ctx context.Context, conn *vpclattice.Client, targetGro func waitRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string, targets []interface{}, timeout time.Duration) (*vpclattice.RegisterTargetsOutput, error) { stateConf := &retry.StateChangeConf{ Pending: enum.Slice(types.TargetStatusInitial), - Target: enum.Slice(types.TargetStatusHealthy, types.TargetStatusUnhealthy), + Target: enum.Slice(types.TargetStatusHealthy, types.TargetStatusUnhealthy, types.TargetStatusUnused, types.TargetStatusUnavailable), Refresh: statusTarget(ctx, conn, id, targets), Timeout: timeout, NotFoundChecks: 20, @@ -230,7 +224,6 @@ func waitRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string } func waitDeleteTargets(ctx context.Context, conn *vpclattice.Client, id string, targets []interface{}, timeout time.Duration) (*vpclattice.DeregisterTargetsOutput, error) { - fmt.Println("Starting Inside Delete waiter") stateConf := &retry.StateChangeConf{ Pending: enum.Slice(types.TargetStatusDraining, types.TargetStatusInitial), Target: []string{}, diff --git a/internal/service/vpclattice/register_targets_test.go b/internal/service/vpclattice/register_targets_test.go index b6adb4bf670a..460c565aa60b 100644 --- a/internal/service/vpclattice/register_targets_test.go +++ b/internal/service/vpclattice/register_targets_test.go @@ -3,11 +3,13 @@ package vpclattice_test import ( "context" "errors" + "fmt" "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" @@ -18,10 +20,13 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -func TestAccVPCLatticeTargets_basic(t *testing.T) { +func TestAccVPCLatticeTargetsRegister_instance(t *testing.T) { ctx := acctest.Context(t) var targets vpclattice.ListTargetsOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_vpclattice_register_targets.test" + instanceId := "aws_instance.test" + targetGroupResourceName := "aws_vpclattice_target_group.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { @@ -31,14 +36,15 @@ func TestAccVPCLatticeTargets_basic(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckTargetGroupDestroy(ctx), + CheckDestroy: testAccCheckTargetsRegisterDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTargets_basic(), + Config: testAccTargetsRegister_instance(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTargetsExists(ctx, resourceName, &targets), - // acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "vpc-lattice", regexp.MustCompile("targetgroup/.+$")), - // resource.TestCheckResourceAttr(resourceName, "config.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, "target_group_identifier"), + resource.TestCheckResourceAttrPair(resourceName, "targets.0.id", instanceId, "id"), + resource.TestCheckResourceAttr(resourceName, "targets.0.port", "80"), ), }, { @@ -50,17 +56,238 @@ func TestAccVPCLatticeTargets_basic(t *testing.T) { }) } -func testAccTargets_basic() string { - return ` -resource "aws_vpclattice_register_targets" "test" { - target_group_identifier = "tg-00153386728e69d10" +func TestAccVPCLatticeTargetsRegister_lambda(t *testing.T) { + ctx := acctest.Context(t) + var targets vpclattice.ListTargetsOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_vpclattice_register_targets.test" + lambdaName := "aws_lambda_function.test" + targetGroupResourceName := "aws_vpclattice_target_group.test" - targets { - id = "i-081f98c4ef2ff21e3x" - port = 80 - } + 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: testAccCheckTargetsRegisterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTargetsRegister_lambda(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTargetsExists(ctx, resourceName, &targets), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, "target_group_identifier"), + resource.TestCheckResourceAttrPair(resourceName, "targets.0.id", lambdaName, "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) } -` + +func TestAccVPCLatticeTargetsRegister_alb(t *testing.T) { + ctx := acctest.Context(t) + var targets vpclattice.ListTargetsOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_vpclattice_register_targets.test" + albName := "aws_lb.test" + targetGroupResourceName := "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: testAccCheckTargetsRegisterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTargetsRegister_alb(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTargetsExists(ctx, resourceName, &targets), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, "target_group_identifier"), + resource.TestCheckResourceAttrPair(resourceName, "targets.0.id", albName, "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccTargetsRegisterConfig_instance(rName string) string { + return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 1), fmt.Sprintf(` + + data "aws_ami" "amzn-ami-minimal-hvm-ebs" { + most_recent = true + owners = ["amazon"] + + filter { + name = "name" + values = ["amzn-ami-minimal-hvm-*"] + } + + filter { + name = "root-device-type" + values = ["ebs"] + } + } + + resource "aws_instance" "test" { + ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = "t2.micro" + subnet_id = aws_subnet.test[0].id + } + +resource "aws_vpclattice_target_group" "test" { + name = %[1]q + type = "INSTANCE" + + config { + port = 80 + protocol = "HTTP" + vpc_identifier = aws_vpc.test.id + } +} +`, rName)) +} + +func testAccTargetsRegister_instance(rName string) string { + return acctest.ConfigCompose(testAccTargetsRegisterConfig_instance(rName), ` + resource "aws_vpclattice_register_targets" "test" { + depends_on = [aws_instance.test] + target_group_identifier = aws_vpclattice_target_group.test.id + + targets { + id = aws_instance.test.id + port = 80 + } + } + +`) +} + +func testAccTargetsRegisterConfig_lambda(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_vpclattice_target_group" "test" { + name = %[1]q + type = "LAMBDA" + + } + +resource "aws_lambda_function" "test" { + filename = "test-fixtures/lambda.zip" + function_name = %[1]q + role = aws_iam_role.test.arn + handler = "lambda_elb.lambda_handler" + runtime = "python3.7" +} + + + +resource "aws_iam_role" "test" { + assume_role_policy = <?AP3FZ+?|&2GPJWbGb$6pd2W)-8{ITeCY1KlZACo@2e>b`PrD~3?yVueXP1DsZUY*lt z^F~MAowU`~=G(nj%|^d3E|RR6BNt@Ceo}A-Uu|*><4-2GE4OyI-Q&D6(QxfX<1!tF zy$3nWGxJksP2;vW|2bZD2EW#WmR%8Qi7`zOeM zdHq~#-89kVQ*}RF+x^#QA7g+wJBO~+@o0TuScAelz?+dtgc%VR$a0{#fPpQIAQnk6 V6X4Ct2GYa`gwa5{3uqk!0|4SRz%l>; literal 0 HcmV?d00001 From 2d14df0c98dc66bf586b2b0d9a9ce5b9f5e89ada Mon Sep 17 00:00:00 2001 From: markos kandylis Date: Sun, 30 Apr 2023 13:42:59 +0100 Subject: [PATCH 09/17] finished tests --- .../service/vpclattice/register_targets.go | 14 +- .../vpclattice/register_targets_test.go | 175 +++++++++++++++--- 2 files changed, 157 insertions(+), 32 deletions(-) diff --git a/internal/service/vpclattice/register_targets.go b/internal/service/vpclattice/register_targets.go index d87a8f595482..b39dcabd860c 100644 --- a/internal/service/vpclattice/register_targets.go +++ b/internal/service/vpclattice/register_targets.go @@ -91,11 +91,12 @@ func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, if v, ok := d.GetOk("targets"); ok && len(v.([]interface{})) > 0 && v.([]interface{}) != nil { targets := expandTargets(v.([]interface{})) - for _, target := range targets { + if len(targets) > 0 { + target := targets[0] log.Printf("[INFO] Registering Target %s with Target Group %s", aws.ToString(target.Id), d.Get("target_group_identifier").(string)) targetId = *target.Id + in.Targets = targets } - in.Targets = targets } out, err := conn.RegisterTargets(ctx, in) @@ -141,7 +142,7 @@ func resourceRegisterTargetsRead(ctx context.Context, d *schema.ResourceData, me if err != nil { return create.DiagError(names.VPCLattice, create.ErrActionReading, ResNameRegisterTargets, d.Id(), err) } - + d.Set("target_group_identifier", targetGroupId) if err := d.Set("targets", flattenTargets(out.Items)); err != nil { return diag.FromErr(fmt.Errorf("error setting targets: %s", err)) } @@ -195,11 +196,8 @@ func findRegisterTargets(ctx context.Context, conn *vpclattice.Client, targetGro return nil, err } - if len(out.Items) == 0 { - out = nil - if out == nil { - return nil, tfresource.NewEmptyResultError(in) - } + if out == nil || out.Items == nil { + return nil, tfresource.NewEmptyResultError(in) } return out, nil diff --git a/internal/service/vpclattice/register_targets_test.go b/internal/service/vpclattice/register_targets_test.go index 460c565aa60b..8b615663042d 100644 --- a/internal/service/vpclattice/register_targets_test.go +++ b/internal/service/vpclattice/register_targets_test.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "strconv" "testing" "github.com/aws/aws-sdk-go-v2/aws" @@ -20,12 +21,12 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -func TestAccVPCLatticeTargetsRegister_instance(t *testing.T) { +func TestAccVPCLatticeRegisterTargets_instance(t *testing.T) { ctx := acctest.Context(t) var targets vpclattice.ListTargetsOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_vpclattice_register_targets.test" - instanceId := "aws_instance.test" + instanceId := "aws_instance.test_instance" targetGroupResourceName := "aws_vpclattice_target_group.test" resource.ParallelTest(t, resource.TestCase{ @@ -36,10 +37,10 @@ func TestAccVPCLatticeTargetsRegister_instance(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckTargetsRegisterDestroy(ctx), + CheckDestroy: testAccCheckRegisterTargetsDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTargetsRegister_instance(rName), + Config: testAccRegisterTargets_instance(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTargetsExists(ctx, resourceName, &targets), resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, "target_group_identifier"), @@ -56,7 +57,43 @@ func TestAccVPCLatticeTargetsRegister_instance(t *testing.T) { }) } -func TestAccVPCLatticeTargetsRegister_lambda(t *testing.T) { +func TestAccVPCLatticeRegisterTargets_ip(t *testing.T) { + ctx := acctest.Context(t) + var targets vpclattice.ListTargetsOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_vpclattice_register_targets.test" + instanceIP := "aws_instance.test_ip" + targetGroupResourceName := "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: testAccCheckRegisterTargetsDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccRegisterTargets_ip(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTargetsExists(ctx, resourceName, &targets), + resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, "target_group_identifier"), + resource.TestCheckResourceAttrPair(resourceName, "targets.0.id", instanceIP, "private_ip"), + resource.TestCheckResourceAttr(resourceName, "targets.0.port", "80"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeRegisterTargets_lambda(t *testing.T) { ctx := acctest.Context(t) var targets vpclattice.ListTargetsOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -72,10 +109,10 @@ func TestAccVPCLatticeTargetsRegister_lambda(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckTargetsRegisterDestroy(ctx), + CheckDestroy: testAccCheckRegisterTargetsDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTargetsRegister_lambda(rName), + Config: testAccRegisterTargets_lambda(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTargetsExists(ctx, resourceName, &targets), resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, "target_group_identifier"), @@ -91,7 +128,7 @@ func TestAccVPCLatticeTargetsRegister_lambda(t *testing.T) { }) } -func TestAccVPCLatticeTargetsRegister_alb(t *testing.T) { +func TestAccVPCLatticeRegisterTargets_alb(t *testing.T) { ctx := acctest.Context(t) var targets vpclattice.ListTargetsOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -107,10 +144,10 @@ func TestAccVPCLatticeTargetsRegister_alb(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckTargetsRegisterDestroy(ctx), + CheckDestroy: testAccCheckRegisterTargetsDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTargetsRegister_alb(rName), + Config: testAccRegisterTargets_alb(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTargetsExists(ctx, resourceName, &targets), resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, "target_group_identifier"), @@ -126,7 +163,7 @@ func TestAccVPCLatticeTargetsRegister_alb(t *testing.T) { }) } -func testAccTargetsRegisterConfig_instance(rName string) string { +func testAccRegisterTargetsConfig_instance(rName string) string { return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 1), fmt.Sprintf(` data "aws_ami" "amzn-ami-minimal-hvm-ebs" { @@ -144,7 +181,7 @@ func testAccTargetsRegisterConfig_instance(rName string) string { } } - resource "aws_instance" "test" { + resource "aws_instance" "test_instance" { ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id instance_type = "t2.micro" subnet_id = aws_subnet.test[0].id @@ -163,14 +200,67 @@ resource "aws_vpclattice_target_group" "test" { `, rName)) } -func testAccTargetsRegister_instance(rName string) string { - return acctest.ConfigCompose(testAccTargetsRegisterConfig_instance(rName), ` +func testAccRegisterTargets_instance(rName string) string { + return acctest.ConfigCompose(testAccRegisterTargetsConfig_instance(rName), ` + resource "aws_vpclattice_register_targets" "test" { + depends_on = [aws_instance.test_instance] + target_group_identifier = aws_vpclattice_target_group.test.id + + targets { + id = aws_instance.test_instance.id + port = 80 + } + } + +`) +} + +func testAccRegisterTargetsConfig_ipAddress(rName string) string { + return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 1), fmt.Sprintf(` + + data "aws_ami" "amzn-ami-minimal-hvm-ebs" { + most_recent = true + owners = ["amazon"] + + filter { + name = "name" + values = ["amzn-ami-minimal-hvm-*"] + } + + filter { + name = "root-device-type" + values = ["ebs"] + } + } + + resource "aws_instance" "test_ip" { + ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = "t2.micro" + subnet_id = aws_subnet.test[0].id + } + +resource "aws_vpclattice_target_group" "test" { + name = %[1]q + type = "IP" + + config { + port = 80 + protocol = "HTTP" + vpc_identifier = aws_vpc.test.id + } +} +`, rName)) +} + +func testAccRegisterTargets_ip(rName string) string { + return acctest.ConfigCompose(testAccRegisterTargetsConfig_ipAddress(rName), ` + resource "aws_vpclattice_register_targets" "test" { - depends_on = [aws_instance.test] + depends_on = [aws_instance.test_ip] target_group_identifier = aws_vpclattice_target_group.test.id targets { - id = aws_instance.test.id + id = aws_instance.test_ip.private_ip port = 80 } } @@ -178,7 +268,7 @@ func testAccTargetsRegister_instance(rName string) string { `) } -func testAccTargetsRegisterConfig_lambda(rName string) string { +func testAccRegisterTargetsConfig_lambda(rName string) string { return fmt.Sprintf(` data "aws_partition" "current" {} @@ -219,8 +309,8 @@ resource "aws_iam_role" "test" { `, rName) } -func testAccTargetsRegister_lambda(rName string) string { - return acctest.ConfigCompose(testAccTargetsRegisterConfig_lambda(rName), ` +func testAccRegisterTargets_lambda(rName string) string { + return acctest.ConfigCompose(testAccRegisterTargetsConfig_lambda(rName), ` resource "aws_vpclattice_register_targets" "test" { depends_on = [aws_lambda_function.test] target_group_identifier = aws_vpclattice_target_group.test.id @@ -233,7 +323,7 @@ func testAccTargetsRegister_lambda(rName string) string { `) } -func testAccTargetsRegisterConfig_alb(rName string) string { +func testAccRegisterTargetsConfig_alb(rName string) string { return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 2), fmt.Sprintf(` resource "aws_vpclattice_target_group" "test" { @@ -275,8 +365,8 @@ resource "aws_vpclattice_target_group" "test" { `, rName)) } -func testAccTargetsRegister_alb(rName string) string { - return acctest.ConfigCompose(testAccTargetsRegisterConfig_alb(rName), ` +func testAccRegisterTargets_alb(rName string) string { + return acctest.ConfigCompose(testAccRegisterTargetsConfig_alb(rName), ` resource "aws_vpclattice_register_targets" "test" { depends_on = [aws_lb.test] target_group_identifier = aws_vpclattice_target_group.test.id @@ -302,8 +392,26 @@ func testAccCheckTargetsExists(ctx context.Context, name string, targets *vpclat } targetGroupIdentifier := rs.Primary.Attributes["target_group_identifier"] + targetID := rs.Primary.Attributes["targets.0.id"] + portStr, hasPort := rs.Primary.Attributes["targets.0.port"] + port, _ := strconv.Atoi(portStr) + hasValidPort := hasPort && port > 0 + + if targetID == "" { + return fmt.Errorf("Error: target ID is empty") + } + target := types.Target{ - Id: aws.String(rs.Primary.Attributes["id"]), + Id: aws.String(targetID), + } + + if hasValidPort { + portStr := rs.Primary.Attributes["targets.0.port"] + port, err := strconv.Atoi(portStr) + if err != nil { + return fmt.Errorf("Error parsing target port: %s", err) + } + target.Port = aws.Int32(int32(port)) } conn := acctest.Provider.Meta().(*conns.AWSClient).VPCLatticeClient() @@ -322,7 +430,7 @@ func testAccCheckTargetsExists(ctx context.Context, name string, targets *vpclat } } -func testAccCheckTargetsRegisterDestroy(ctx context.Context) resource.TestCheckFunc { +func testAccCheckRegisterTargetsDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).VPCLatticeClient() @@ -332,10 +440,29 @@ func testAccCheckTargetsRegisterDestroy(ctx context.Context) resource.TestCheckF } targetGroupIdentifier := rs.Primary.Attributes["target_group_identifier"] + targetID := rs.Primary.Attributes["targets.0.id"] + portStr, hasPort := rs.Primary.Attributes["targets.0.port"] + port, _ := strconv.Atoi(portStr) + hasValidPort := hasPort && port > 0 + + target := types.Target{ + Id: aws.String(targetID), + } + + if hasValidPort { + portStr := rs.Primary.Attributes["targets.0.port"] + port, err := strconv.Atoi(portStr) + if err != nil { + return fmt.Errorf("Error parsing target port: %s", err) + } + target.Port = aws.Int32(int32(port)) + } _, err := conn.ListTargets(ctx, &vpclattice.ListTargetsInput{ TargetGroupIdentifier: aws.String(targetGroupIdentifier), + Targets: []types.Target{target}, }) + if err != nil { var nfe *types.ResourceNotFoundException if errors.As(err, &nfe) { From 97f65ba01d92f51600f484a233a60bbcafae99df Mon Sep 17 00:00:00 2001 From: markos kandylis Date: Sun, 30 Apr 2023 17:00:45 +0100 Subject: [PATCH 10/17] Run all tests --- .changelog/31039.txt | 3 + .../service/vpclattice/register_targets.go | 7 +- .../vpclattice/register_targets_test.go | 239 +++++++++--------- .../vpclattice_register_targets.html.markdown | 37 +-- 4 files changed, 143 insertions(+), 143 deletions(-) create mode 100644 .changelog/31039.txt diff --git a/.changelog/31039.txt b/.changelog/31039.txt new file mode 100644 index 000000000000..2d7503d93d54 --- /dev/null +++ b/.changelog/31039.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_vpclattice_register_targets +``` \ No newline at end of file diff --git a/internal/service/vpclattice/register_targets.go b/internal/service/vpclattice/register_targets.go index b39dcabd860c..58852fe233e2 100644 --- a/internal/service/vpclattice/register_targets.go +++ b/internal/service/vpclattice/register_targets.go @@ -52,7 +52,7 @@ func ResourceRegisterTargets() *schema.Resource { }, "targets": { Type: schema.TypeList, - Optional: true, + Required: true, ForceNew: true, MaxItems: 1, MinItems: 1, @@ -60,7 +60,7 @@ func ResourceRegisterTargets() *schema.Resource { Schema: map[string]*schema.Schema{ "id": { Type: schema.TypeString, - Optional: true, + Required: true, ForceNew: true, ValidateFunc: validation.StringLenBetween(1, 2048), }, @@ -94,7 +94,7 @@ func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, if len(targets) > 0 { target := targets[0] log.Printf("[INFO] Registering Target %s with Target Group %s", aws.ToString(target.Id), d.Get("target_group_identifier").(string)) - targetId = *target.Id + targetId = aws.ToString(target.Id) in.Targets = targets } } @@ -151,7 +151,6 @@ func resourceRegisterTargetsRead(ctx context.Context, d *schema.ResourceData, me } func resourceRegisterTargetsDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - conn := meta.(*conns.AWSClient).VPCLatticeClient() targetGroupIdentifier := d.Get("target_group_identifier").(string) diff --git a/internal/service/vpclattice/register_targets_test.go b/internal/service/vpclattice/register_targets_test.go index 8b615663042d..f205a6c6c831 100644 --- a/internal/service/vpclattice/register_targets_test.go +++ b/internal/service/vpclattice/register_targets_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" ) @@ -166,30 +165,32 @@ func TestAccVPCLatticeRegisterTargets_alb(t *testing.T) { func testAccRegisterTargetsConfig_instance(rName string) string { return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 1), fmt.Sprintf(` - data "aws_ami" "amzn-ami-minimal-hvm-ebs" { - most_recent = true - owners = ["amazon"] - - filter { - name = "name" - values = ["amzn-ami-minimal-hvm-*"] - } - - filter { - name = "root-device-type" - values = ["ebs"] - } - } - - resource "aws_instance" "test_instance" { - ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id - instance_type = "t2.micro" - subnet_id = aws_subnet.test[0].id - } + +data "aws_ami" "amzn-ami-minimal-hvm-ebs" { + most_recent = true + owners = ["amazon"] + + filter { + name = "name" + values = ["amzn-ami-minimal-hvm-*"] + } + + filter { + name = "root-device-type" + values = ["ebs"] + } +} + +resource "aws_instance" "test_instance" { + ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = "t3.large" + subnet_id = aws_subnet.test[0].id +} resource "aws_vpclattice_target_group" "test" { - name = %[1]q - type = "INSTANCE" + depends_on = [aws_instance.test_instance] + name = %[1]q + type = "INSTANCE" config { port = 80 @@ -202,15 +203,16 @@ resource "aws_vpclattice_target_group" "test" { func testAccRegisterTargets_instance(rName string) string { return acctest.ConfigCompose(testAccRegisterTargetsConfig_instance(rName), ` - resource "aws_vpclattice_register_targets" "test" { - depends_on = [aws_instance.test_instance] - target_group_identifier = aws_vpclattice_target_group.test.id - - targets { - id = aws_instance.test_instance.id - port = 80 - } - } +resource "aws_vpclattice_register_targets" "test" { + depends_on = [aws_vpclattice_target_group.test] + target_group_identifier = aws_vpclattice_target_group.test.id + + targets { + id = aws_instance.test_instance.id + port = 80 + } +} + `) } @@ -218,30 +220,32 @@ func testAccRegisterTargets_instance(rName string) string { func testAccRegisterTargetsConfig_ipAddress(rName string) string { return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 1), fmt.Sprintf(` - data "aws_ami" "amzn-ami-minimal-hvm-ebs" { - most_recent = true - owners = ["amazon"] - - filter { - name = "name" - values = ["amzn-ami-minimal-hvm-*"] - } - - filter { - name = "root-device-type" - values = ["ebs"] - } - } - - resource "aws_instance" "test_ip" { - ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id - instance_type = "t2.micro" - subnet_id = aws_subnet.test[0].id - } + +data "aws_ami" "amzn-ami-minimal-hvm-ebs" { + most_recent = true + owners = ["amazon"] + + filter { + name = "name" + values = ["amzn-ami-minimal-hvm-*"] + } + + filter { + name = "root-device-type" + values = ["ebs"] + } +} + +resource "aws_instance" "test_ip" { + ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = "t3.large" + subnet_id = aws_subnet.test[0].id +} resource "aws_vpclattice_target_group" "test" { - name = %[1]q - type = "IP" + depends_on = [aws_instance.test_ip] + name = %[1]q + type = "IP" config { port = 80 @@ -255,15 +259,17 @@ resource "aws_vpclattice_target_group" "test" { func testAccRegisterTargets_ip(rName string) string { return acctest.ConfigCompose(testAccRegisterTargetsConfig_ipAddress(rName), ` - resource "aws_vpclattice_register_targets" "test" { - depends_on = [aws_instance.test_ip] - target_group_identifier = aws_vpclattice_target_group.test.id - - targets { - id = aws_instance.test_ip.private_ip - port = 80 - } - } + +resource "aws_vpclattice_register_targets" "test" { + depends_on = [aws_vpclattice_target_group.test] + target_group_identifier = aws_vpclattice_target_group.test.id + + targets { + id = aws_instance.test_ip.private_ip + port = 80 + } +} + `) } @@ -273,10 +279,11 @@ func testAccRegisterTargetsConfig_lambda(rName string) string { data "aws_partition" "current" {} resource "aws_vpclattice_target_group" "test" { - name = %[1]q - type = "LAMBDA" - - } + depends_on = [aws_lambda_function.test] + name = %[1]q + type = "LAMBDA" + +} resource "aws_lambda_function" "test" { filename = "test-fixtures/lambda.zip" @@ -311,14 +318,15 @@ resource "aws_iam_role" "test" { func testAccRegisterTargets_lambda(rName string) string { return acctest.ConfigCompose(testAccRegisterTargetsConfig_lambda(rName), ` - resource "aws_vpclattice_register_targets" "test" { - depends_on = [aws_lambda_function.test] - target_group_identifier = aws_vpclattice_target_group.test.id - - targets { - id = aws_lambda_function.test.arn - } - } +resource "aws_vpclattice_register_targets" "test" { + depends_on = [aws_vpclattice_target_group.test] + target_group_identifier = aws_vpclattice_target_group.test.id + + targets { + id = aws_lambda_function.test.arn + } +} + `) } @@ -326,56 +334,59 @@ func testAccRegisterTargets_lambda(rName string) string { func testAccRegisterTargetsConfig_alb(rName string) string { return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 2), fmt.Sprintf(` + resource "aws_vpclattice_target_group" "test" { - name = %[1]q - type = "ALB" - - config { - port = 80 - protocol = "HTTP" - vpc_identifier = aws_vpc.test.id - } - } + name = %[1]q + type = "ALB" - resource "aws_lb" "test" { - name = %[1]q - internal = true - load_balancer_type = "application" - subnets = [aws_subnet.test[0].id, aws_subnet.test[1].id] - - enable_deletion_protection = false - + config { + port = 80 + protocol = "HTTP" + vpc_identifier = aws_vpc.test.id } +} - resource "aws_lb_listener" "test" { - load_balancer_arn = aws_lb.test.arn - port = "80" - protocol = "HTTP" - default_action { - type = "fixed-response" - - fixed_response { - content_type = "text/plain" - message_body = "Fixed response content" - status_code = "200" - } - } +resource "aws_lb" "test" { + name = %[1]q + internal = true + load_balancer_type = "application" + subnets = [aws_subnet.test[0].id, aws_subnet.test[1].id] + + enable_deletion_protection = false + +} + +resource "aws_lb_listener" "test" { + load_balancer_arn = aws_lb.test.arn + port = "80" + protocol = "HTTP" + default_action { + type = "fixed-response" + + fixed_response { + content_type = "text/plain" + message_body = "Fixed response content" + status_code = "200" + } } +} + `, rName)) } func testAccRegisterTargets_alb(rName string) string { return acctest.ConfigCompose(testAccRegisterTargetsConfig_alb(rName), ` - resource "aws_vpclattice_register_targets" "test" { - depends_on = [aws_lb.test] - target_group_identifier = aws_vpclattice_target_group.test.id - - targets { - id = aws_lb.test.arn - port = 80 - } - } +resource "aws_vpclattice_register_targets" "test" { + depends_on = [aws_lb.test] + target_group_identifier = aws_vpclattice_target_group.test.id + + targets { + id = aws_lb.test.arn + port = 80 + } +} + `) } diff --git a/website/docs/r/vpclattice_register_targets.html.markdown b/website/docs/r/vpclattice_register_targets.html.markdown index e98fd43f8be0..b5e7786ef610 100644 --- a/website/docs/r/vpclattice_register_targets.html.markdown +++ b/website/docs/r/vpclattice_register_targets.html.markdown @@ -16,6 +16,13 @@ Terraform resource for managing an AWS VPC Lattice Register Targets. ```terraform resource "aws_vpclattice_register_targets" "example" { + + target_group_identifier = aws_vpclattice_target_group.example.id + + targets { + id = aws_lb.example.arn + port = 80 + } } ``` @@ -23,31 +30,11 @@ resource "aws_vpclattice_register_targets" "example" { The following arguments are required: -* `example_arg` - (Required) Concise argument description. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. - -The following arguments are optional: - -* `optional_arg` - (Optional) Concise argument description. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. - -## Attributes Reference - -In addition to all arguments above, the following attributes are exported: +- `target_group_identifier` - (Required) The ID or Amazon Resource Name (ARN) of the target group. +- `targets` - (Required) The target. -* `arn` - ARN of the Register Targets. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. -* `example_attribute` - Concise description. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. +targets (`targets`) supports the following: -## Timeouts +- `id` - (Required) The ID of the target. If the target type of the target group is INSTANCE, this is an instance ID. If the target type is IP , this is an IP address. If the target type is LAMBDA, this is the ARN of the Lambda function. If the target type is ALB, this is the ARN of the Application Load Balancer. -[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): - -* `create` - (Default `60m`) -* `update` - (Default `180m`) -* `delete` - (Default `90m`) - -## Import - -VPC Lattice Register Targets can be imported using the `example_id_arg`, e.g., - -``` -$ terraform import aws_vpclattice_register_targets.example rft-8012925589 -``` +- `port` - (Optional) The port on which the target is listening. For HTTP, the default is 80. For HTTPS, the default is 443. From 92e1613e556645c9eaedc439b3f355939c494ea7 Mon Sep 17 00:00:00 2001 From: markos kandylis Date: Sun, 30 Apr 2023 17:32:16 +0100 Subject: [PATCH 11/17] added Attributes Referance for the docs --- website/docs/r/vpclattice_register_targets.html.markdown | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/website/docs/r/vpclattice_register_targets.html.markdown b/website/docs/r/vpclattice_register_targets.html.markdown index b5e7786ef610..9df4f13f8e05 100644 --- a/website/docs/r/vpclattice_register_targets.html.markdown +++ b/website/docs/r/vpclattice_register_targets.html.markdown @@ -38,3 +38,9 @@ targets (`targets`) supports the following: - `id` - (Required) The ID of the target. If the target type of the target group is INSTANCE, this is an instance ID. If the target type is IP , this is an IP address. If the target type is LAMBDA, this is the ARN of the Lambda function. If the target type is ALB, this is the ARN of the Application Load Balancer. - `port` - (Optional) The port on which the target is listening. For HTTP, the default is 80. For HTTPS, the default is 443. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +- `id` - id of the target register. From 23464d4e42123806a00a83027959877edf45131d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 2 May 2023 10:42:47 -0400 Subject: [PATCH 12/17] 'aws_vpclattice_register_targets' -> 'aws_vpclattice_target_group_attachment'. --- .changelog/31039.txt | 2 +- internal/service/vpclattice/exports_test.go | 8 + .../service/vpclattice/register_targets.go | 328 ------------------ .../service/vpclattice/service_package_gen.go | 10 +- .../vpclattice/target_group_attachment.go | 274 +++++++++++++++ ...est.go => target_group_attachment_test.go} | 113 ++---- ...ice_target_group_attachment.html.markdown} | 22 +- 7 files changed, 328 insertions(+), 429 deletions(-) create mode 100644 internal/service/vpclattice/exports_test.go delete mode 100644 internal/service/vpclattice/register_targets.go create mode 100644 internal/service/vpclattice/target_group_attachment.go rename internal/service/vpclattice/{register_targets_test.go => target_group_attachment_test.go} (75%) rename website/docs/r/{vpclattice_register_targets.html.markdown => vpclattice_target_group_attachment.html.markdown} (63%) diff --git a/.changelog/31039.txt b/.changelog/31039.txt index 2d7503d93d54..b9f70967ecf8 100644 --- a/.changelog/31039.txt +++ b/.changelog/31039.txt @@ -1,3 +1,3 @@ ```release-note:new-resource -aws_vpclattice_register_targets +aws_vpclattice_target_group_attachment ``` \ No newline at end of file diff --git a/internal/service/vpclattice/exports_test.go b/internal/service/vpclattice/exports_test.go new file mode 100644 index 000000000000..de5ad314c184 --- /dev/null +++ b/internal/service/vpclattice/exports_test.go @@ -0,0 +1,8 @@ +package vpclattice + +// Exports for use in tests only. +var ( + FindTargetByThreePartKey = findTargetByThreePartKey + + ResourceTargetGroupAttachment = resourceTargetGroupAttachment +) diff --git a/internal/service/vpclattice/register_targets.go b/internal/service/vpclattice/register_targets.go deleted file mode 100644 index 58852fe233e2..000000000000 --- a/internal/service/vpclattice/register_targets.go +++ /dev/null @@ -1,328 +0,0 @@ -package vpclattice - -import ( - "context" - "errors" - "fmt" - "log" - "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/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" - "github.com/hashicorp/terraform-provider-aws/internal/create" - "github.com/hashicorp/terraform-provider-aws/internal/enum" - "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - "github.com/hashicorp/terraform-provider-aws/names" -) - -// Function annotations are used for resource registration to the Provider. DO NOT EDIT. -// @SDKResource("aws_vpclattice_register_targets", name="Register Targets") -func ResourceRegisterTargets() *schema.Resource { - return &schema.Resource{ - CreateWithoutTimeout: resourceRegisterTargetsCreate, - ReadWithoutTimeout: resourceRegisterTargetsRead, - DeleteWithoutTimeout: resourceRegisterTargetsDelete, - - Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - idParts := strings.Split(d.Id(), "/") - d.Set("target_group_identifier", idParts[0]) - - return []*schema.ResourceData{d}, nil - }, - }, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(30 * time.Minute), - Delete: schema.DefaultTimeout(30 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - "target_group_identifier": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "targets": { - Type: schema.TypeList, - Required: true, - ForceNew: true, - MaxItems: 1, - MinItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringLenBetween(1, 2048), - }, - "port": { - Type: schema.TypeInt, - Optional: true, - ForceNew: true, - }, - }, - }, - }, - }, - } -} - -const ( - ResNameRegisterTargets = "Register Targets" -) - -func resourceRegisterTargetsCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - conn := meta.(*conns.AWSClient).VPCLatticeClient() - - in := &vpclattice.RegisterTargetsInput{ - TargetGroupIdentifier: aws.String(d.Get("target_group_identifier").(string)), - } - - var targetId string - if v, ok := d.GetOk("targets"); ok && len(v.([]interface{})) > 0 && v.([]interface{}) != nil { - targets := expandTargets(v.([]interface{})) - - if len(targets) > 0 { - target := targets[0] - log.Printf("[INFO] Registering Target %s with Target Group %s", aws.ToString(target.Id), d.Get("target_group_identifier").(string)) - targetId = aws.ToString(target.Id) - in.Targets = targets - } - } - - out, err := conn.RegisterTargets(ctx, in) - if err != nil { - return create.DiagError(names.VPCLattice, create.ErrActionCreating, ResNameRegisterTargets, d.Get("target_group_identifier").(string), err) - } - - if out == nil { - return create.DiagError(names.VPCLattice, create.ErrActionCreating, ResNameRegisterTargets, d.Get("target_group_identifier").(string), errors.New("empty output")) - } - - targetGroupIdentifier := d.Get("target_group_identifier").(string) - targets := d.Get("targets").([]interface{}) - - parts := []string{ - d.Get("target_group_identifier").(string), - targetId, - } - - d.SetId(strings.Join(parts, "/")) - - if _, err := waitRegisterTargets(ctx, conn, targetGroupIdentifier, targets, d.Timeout(schema.TimeoutCreate)); err != nil { - return create.DiagError(names.VPCLattice, create.ErrActionWaitingForCreation, ResNameRegisterTargets, d.Id(), err) - } - - return resourceRegisterTargetsRead(ctx, d, meta) -} - -func resourceRegisterTargetsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - conn := meta.(*conns.AWSClient).VPCLatticeClient() - - targetGroupId := d.Get("target_group_identifier").(string) - targets := d.Get("targets").([]interface{}) - - out, err := findRegisterTargets(ctx, conn, targetGroupId, targets) - - if !d.IsNewResource() && tfresource.NotFound(err) { - log.Printf("[WARN] VpcLattice RegisterTargets (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - - if err != nil { - return create.DiagError(names.VPCLattice, create.ErrActionReading, ResNameRegisterTargets, d.Id(), err) - } - d.Set("target_group_identifier", targetGroupId) - if err := d.Set("targets", flattenTargets(out.Items)); err != nil { - return diag.FromErr(fmt.Errorf("error setting targets: %s", err)) - } - - return nil -} - -func resourceRegisterTargetsDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - conn := meta.(*conns.AWSClient).VPCLatticeClient() - - targetGroupIdentifier := d.Get("target_group_identifier").(string) - targetsRaw := d.Get("targets").([]interface{}) - targets := expandTargets(targetsRaw) - - _, err := conn.DeregisterTargets(ctx, &vpclattice.DeregisterTargetsInput{ - TargetGroupIdentifier: aws.String(targetGroupIdentifier), - Targets: targets, - }) - - if err != nil { - var nfe *types.ResourceNotFoundException - if errors.As(err, &nfe) { - return nil - } - - return create.DiagError(names.VPCLattice, create.ErrActionDeleting, ResNameRegisterTargets, d.Id(), err) - } - if _, err := waitDeleteTargets(ctx, conn, targetGroupIdentifier, targetsRaw, d.Timeout(schema.TimeoutDelete)); err != nil { - return create.DiagError(names.VPCLattice, create.ErrActionWaitingForDeletion, ResNameRegisterTargets, d.Id(), err) - } - - return nil -} - -func findRegisterTargets(ctx context.Context, conn *vpclattice.Client, targetGroupId string, targets []interface{}) (*vpclattice.ListTargetsOutput, error) { - in := &vpclattice.ListTargetsInput{ - TargetGroupIdentifier: aws.String(targetGroupId), - Targets: expandTargets(targets), - } - out, err := conn.ListTargets(ctx, in) - if err != nil { - var nfe *types.ResourceNotFoundException - if errors.As(err, &nfe) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: in, - } - } - - return nil, err - } - - if out == nil || out.Items == nil { - return nil, tfresource.NewEmptyResultError(in) - } - - return out, nil -} - -func waitRegisterTargets(ctx context.Context, conn *vpclattice.Client, id string, targets []interface{}, timeout time.Duration) (*vpclattice.RegisterTargetsOutput, error) { - stateConf := &retry.StateChangeConf{ - Pending: enum.Slice(types.TargetStatusInitial), - Target: enum.Slice(types.TargetStatusHealthy, types.TargetStatusUnhealthy, types.TargetStatusUnused, types.TargetStatusUnavailable), - Refresh: statusTarget(ctx, conn, id, targets), - Timeout: timeout, - NotFoundChecks: 20, - ContinuousTargetOccurence: 2, - } - - outputRaw, err := stateConf.WaitForStateContext(ctx) - if out, ok := outputRaw.(*vpclattice.RegisterTargetsOutput); ok { - return out, err - } - - return nil, err -} - -func waitDeleteTargets(ctx context.Context, conn *vpclattice.Client, id string, targets []interface{}, timeout time.Duration) (*vpclattice.DeregisterTargetsOutput, error) { - stateConf := &retry.StateChangeConf{ - Pending: enum.Slice(types.TargetStatusDraining, types.TargetStatusInitial), - Target: []string{}, - Refresh: statusTarget(ctx, conn, id, targets), - Timeout: timeout, - } - - outputRaw, err := stateConf.WaitForStateContext(ctx) - if out, ok := outputRaw.(*vpclattice.DeregisterTargetsOutput); ok { - return out, err - } - - return nil, err -} - -func statusTarget(ctx context.Context, conn *vpclattice.Client, id string, targets []interface{}) retry.StateRefreshFunc { - return func() (interface{}, string, error) { - out, err := findRegisterTargets(ctx, conn, id, targets) - if tfresource.NotFound(err) { - return nil, "", nil - } - - if err != nil { - return nil, "", err - } - - var status types.TargetStatus - if len(out.Items) > 0 { - status = out.Items[0].Status - return out, string(status), nil - } - - return nil, "", err - } -} - -// Flatten function for targets -func flattenTargets(apiObjects []types.TargetSummary) []interface{} { - if len(apiObjects) == 0 { - return nil - } - - var tfList []interface{} - - for _, apiObject := range apiObjects { - tfList = append(tfList, flattenTarget(&apiObject)) - } - - return tfList -} - -func flattenTarget(apiObject *types.TargetSummary) map[string]interface{} { - if apiObject == nil { - return nil - } - - tfMap := map[string]interface{}{} - - if v := apiObject.Id; v != nil { - tfMap["id"] = aws.ToString(v) - } - - if v := apiObject.Port; v != nil { - tfMap["port"] = aws.ToInt32(v) - } - - return tfMap -} - -// Expand function for targets -func expandTargets(tfList []interface{}) []types.Target { - if len(tfList) == 0 { - return nil - } - - var apiObjects []types.Target - - for _, tfMapRaw := range tfList { - tfMap, ok := tfMapRaw.(map[string]interface{}) - - if !ok { - continue - } - - apiObject := expandTarget(tfMap) - - apiObjects = append(apiObjects, apiObject) - } - - return apiObjects -} - -func expandTarget(tfMap map[string]interface{}) types.Target { - apiObject := types.Target{} - - if v, ok := tfMap["id"].(string); ok && v != "" { - apiObject.Id = aws.String(v) - } - - if v, ok := tfMap["port"].(int); ok && v != 0 { - apiObject.Port = aws.Int32(int32(v)) - } - - return apiObject -} diff --git a/internal/service/vpclattice/service_package_gen.go b/internal/service/vpclattice/service_package_gen.go index 85ffda0d9fd1..1b5a81adadf2 100644 --- a/internal/service/vpclattice/service_package_gen.go +++ b/internal/service/vpclattice/service_package_gen.go @@ -72,11 +72,6 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka IdentifierAttribute: "arn", }, }, - { - Factory: ResourceRegisterTargets, - TypeName: "aws_vpclattice_register_targets", - Name: "Register Targets", - }, { Factory: ResourceResourcePolicy, TypeName: "aws_vpclattice_resource_policy", @@ -122,6 +117,11 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka IdentifierAttribute: "arn", }, }, + { + Factory: resourceTargetGroupAttachment, + TypeName: "aws_vpclattice_target_group_attachment", + Name: "Target Group Attachment", + }, } } diff --git a/internal/service/vpclattice/target_group_attachment.go b/internal/service/vpclattice/target_group_attachment.go new file mode 100644 index 000000000000..1ba35715e5d5 --- /dev/null +++ b/internal/service/vpclattice/target_group_attachment.go @@ -0,0 +1,274 @@ +package vpclattice + +import ( + "context" + "errors" + "log" + "strconv" + "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/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" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" +) + +// @SDKResource("aws_vpclattice_target_group_attachment", name="Target Group Attachment") +func resourceTargetGroupAttachment() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: resourceTargetGroupAttachmentCreate, + ReadWithoutTimeout: resourceTargetGroupAttachmentRead, + DeleteWithoutTimeout: resourceTargetGroupAttachmentDelete, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "target": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + MaxItems: 1, + MinItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 2048), + }, + "port": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + ValidateFunc: validation.IsPortNumber, + }, + }, + }, + }, + "target_group_identifier": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceTargetGroupAttachmentCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).VPCLatticeClient() + + targetGroupID := d.Get("target_group_identifier").(string) + target := expandTarget(d.Get("target").([]interface{})[0].(map[string]interface{})) + targetID := aws.ToString(target.Id) + targetPort := int(aws.ToInt32(target.Port)) + id := strings.Join([]string{targetGroupID, targetID, strconv.Itoa(targetPort)}, "/") + input := &vpclattice.RegisterTargetsInput{ + TargetGroupIdentifier: aws.String(targetGroupID), + Targets: []types.Target{target}, + } + + _, err := conn.RegisterTargets(ctx, input) + + if err != nil { + return diag.Errorf("creating VPC Lattice Target Group Attachment (%s): %s", id, err) + } + + d.SetId(id) + + if _, err := waitTargetGroupAttachmentCreated(ctx, conn, targetGroupID, targetID, targetPort, d.Timeout(schema.TimeoutCreate)); err != nil { + return diag.Errorf("waiting for VPC Lattice Target Group Attachment (%s) create: %s", id, err) + } + + return resourceTargetGroupAttachmentRead(ctx, d, meta) +} + +func resourceTargetGroupAttachmentRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).VPCLatticeClient() + + targetGroupID := d.Get("target_group_identifier").(string) + target := expandTarget(d.Get("target").([]interface{})[0].(map[string]interface{})) + targetID := aws.ToString(target.Id) + targetPort := int(aws.ToInt32(target.Port)) + + output, err := findTargetByThreePartKey(ctx, conn, targetGroupID, targetID, targetPort) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] VPC Lattice Target Group Attachment (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return diag.Errorf("reading VPC Lattice Target Group Attachment (%s): %s", d.Id(), err) + } + + if err := d.Set("target", []interface{}{flattenTargetSummary(output)}); err != nil { + return diag.Errorf("setting target: %s", err) + } + d.Set("target_group_identifier", targetGroupID) + + return nil +} + +func resourceTargetGroupAttachmentDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).VPCLatticeClient() + + targetGroupID := d.Get("target_group_identifier").(string) + target := expandTarget(d.Get("target").([]interface{})[0].(map[string]interface{})) + targetID := aws.ToString(target.Id) + targetPort := int(aws.ToInt32(target.Port)) + + log.Printf("[INFO] Deleting VPC Lattice Target Group Attachment: %s", d.Id()) + _, err := conn.DeregisterTargets(ctx, &vpclattice.DeregisterTargetsInput{ + TargetGroupIdentifier: aws.String(targetGroupID), + Targets: []types.Target{target}, + }) + + if errs.IsA[*types.ResourceNotFoundException](err) { + return nil + } + + if err != nil { + return diag.Errorf("deleting VPC Lattice Target Group Attachment (%s): %s", d.Id(), err) + } + + if _, err := waitTargetGroupAttachmentDeleted(ctx, conn, targetGroupID, targetID, targetPort, d.Timeout(schema.TimeoutDelete)); err != nil { + return diag.Errorf("waiting for VPC Lattice Target Group Attachment (%s) delete: %s", d.Id(), err) + } + + return nil +} + +func findTargetByThreePartKey(ctx context.Context, conn *vpclattice.Client, targetGroupID, targetID string, targetPort int) (*types.TargetSummary, error) { + input := &vpclattice.ListTargetsInput{ + TargetGroupIdentifier: aws.String(targetGroupID), + Targets: []types.Target{{ + Id: aws.String(targetID), + }}, + } + if targetPort > 0 { + input.Targets[0].Port = aws.Int32(int32(targetPort)) + } + + paginator := vpclattice.NewListTargetsPaginator(conn, input) + for paginator.HasMorePages() { + output, err := paginator.NextPage(ctx) + + if errs.IsA[*types.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output != nil && len(output.Items) == 1 { + return &(output.Items[0]), nil + } + } + + return nil, &retry.NotFoundError{} +} + +func statusTarget(ctx context.Context, conn *vpclattice.Client, targetGroupID, targetID string, targetPort int) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := findTargetByThreePartKey(ctx, conn, targetGroupID, targetID, targetPort) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, string(output.Status), nil + } +} + +func waitTargetGroupAttachmentCreated(ctx context.Context, conn *vpclattice.Client, targetGroupID, targetID string, targetPort int, timeout time.Duration) (*types.TargetSummary, error) { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice(types.TargetStatusInitial), + Target: enum.Slice(types.TargetStatusHealthy, types.TargetStatusUnhealthy, types.TargetStatusUnused, types.TargetStatusUnavailable), + Refresh: statusTarget(ctx, conn, targetGroupID, targetID, targetPort), + Timeout: timeout, + NotFoundChecks: 20, + ContinuousTargetOccurence: 2, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*types.TargetSummary); ok { + tfresource.SetLastError(err, errors.New(aws.ToString(output.ReasonCode))) + + return output, err + } + + return nil, err +} + +func waitTargetGroupAttachmentDeleted(ctx context.Context, conn *vpclattice.Client, targetGroupID, targetID string, targetPort int, timeout time.Duration) (*types.TargetSummary, error) { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice(types.TargetStatusDraining, types.TargetStatusInitial), + Target: []string{}, + Refresh: statusTarget(ctx, conn, targetGroupID, targetID, targetPort), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*types.TargetSummary); ok { + tfresource.SetLastError(err, errors.New(aws.ToString(output.ReasonCode))) + + return output, err + } + + return nil, err +} + +func flattenTargetSummary(apiObject *types.TargetSummary) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.Id; v != nil { + tfMap["id"] = aws.ToString(v) + } + + if v := apiObject.Port; v != nil { + tfMap["port"] = aws.ToInt32(v) + } + + return tfMap +} + +func expandTarget(tfMap map[string]interface{}) types.Target { + apiObject := types.Target{} + + if v, ok := tfMap["id"].(string); ok && v != "" { + apiObject.Id = aws.String(v) + } + + if v, ok := tfMap["port"].(int); ok && v != 0 { + apiObject.Port = aws.Int32(int32(v)) + } + + return apiObject +} diff --git a/internal/service/vpclattice/register_targets_test.go b/internal/service/vpclattice/target_group_attachment_test.go similarity index 75% rename from internal/service/vpclattice/register_targets_test.go rename to internal/service/vpclattice/target_group_attachment_test.go index f205a6c6c831..8698f0297e9c 100644 --- a/internal/service/vpclattice/register_targets_test.go +++ b/internal/service/vpclattice/target_group_attachment_test.go @@ -2,27 +2,22 @@ package vpclattice_test import ( "context" - "errors" "fmt" "strconv" "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/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) -func TestAccVPCLatticeRegisterTargets_instance(t *testing.T) { +func TestAccVPCLatticeTargetGroupAttachment_instance(t *testing.T) { ctx := acctest.Context(t) - var targets vpclattice.ListTargetsOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_vpclattice_register_targets.test" instanceId := "aws_instance.test_instance" @@ -41,24 +36,18 @@ func TestAccVPCLatticeRegisterTargets_instance(t *testing.T) { { Config: testAccRegisterTargets_instance(rName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckTargetsExists(ctx, resourceName, &targets), + testAccCheckTargetsExists(ctx, resourceName), resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, "target_group_identifier"), resource.TestCheckResourceAttrPair(resourceName, "targets.0.id", instanceId, "id"), resource.TestCheckResourceAttr(resourceName, "targets.0.port", "80"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, }, }) } -func TestAccVPCLatticeRegisterTargets_ip(t *testing.T) { +func TestAccVPCLatticeTargetGroupAttachment_ip(t *testing.T) { ctx := acctest.Context(t) - var targets vpclattice.ListTargetsOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_vpclattice_register_targets.test" instanceIP := "aws_instance.test_ip" @@ -77,24 +66,18 @@ func TestAccVPCLatticeRegisterTargets_ip(t *testing.T) { { Config: testAccRegisterTargets_ip(rName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckTargetsExists(ctx, resourceName, &targets), + testAccCheckTargetsExists(ctx, resourceName), resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, "target_group_identifier"), resource.TestCheckResourceAttrPair(resourceName, "targets.0.id", instanceIP, "private_ip"), resource.TestCheckResourceAttr(resourceName, "targets.0.port", "80"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, }, }) } -func TestAccVPCLatticeRegisterTargets_lambda(t *testing.T) { +func TestAccVPCLatticeTargetGroupAttachment_lambda(t *testing.T) { ctx := acctest.Context(t) - var targets vpclattice.ListTargetsOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_vpclattice_register_targets.test" lambdaName := "aws_lambda_function.test" @@ -113,7 +96,7 @@ func TestAccVPCLatticeRegisterTargets_lambda(t *testing.T) { { Config: testAccRegisterTargets_lambda(rName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckTargetsExists(ctx, resourceName, &targets), + testAccCheckTargetsExists(ctx, resourceName), resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, "target_group_identifier"), resource.TestCheckResourceAttrPair(resourceName, "targets.0.id", lambdaName, "arn"), ), @@ -127,9 +110,8 @@ func TestAccVPCLatticeRegisterTargets_lambda(t *testing.T) { }) } -func TestAccVPCLatticeRegisterTargets_alb(t *testing.T) { +func TestAccVPCLatticeTargetGroupAttachment_alb(t *testing.T) { ctx := acctest.Context(t) - var targets vpclattice.ListTargetsOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_vpclattice_register_targets.test" albName := "aws_lb.test" @@ -148,7 +130,7 @@ func TestAccVPCLatticeRegisterTargets_alb(t *testing.T) { { Config: testAccRegisterTargets_alb(rName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckTargetsExists(ctx, resourceName, &targets), + testAccCheckTargetsExists(ctx, resourceName), resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, "target_group_identifier"), resource.TestCheckResourceAttrPair(resourceName, "targets.0.id", albName, "arn"), ), @@ -391,53 +373,32 @@ resource "aws_vpclattice_register_targets" "test" { `) } -func testAccCheckTargetsExists(ctx context.Context, name string, targets *vpclattice.ListTargetsOutput) resource.TestCheckFunc { +func testAccCheckTargetsExists(ctx context.Context, n string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[n] if !ok { - return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameRegisterTargets, name, errors.New("not found")) + return fmt.Errorf("Not found: %s", n) } if rs.Primary.ID == "" { - return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameRegisterTargets, name, errors.New("not set")) - } - - targetGroupIdentifier := rs.Primary.Attributes["target_group_identifier"] - targetID := rs.Primary.Attributes["targets.0.id"] - portStr, hasPort := rs.Primary.Attributes["targets.0.port"] - port, _ := strconv.Atoi(portStr) - hasValidPort := hasPort && port > 0 - - if targetID == "" { - return fmt.Errorf("Error: target ID is empty") + return fmt.Errorf("No VPC Lattice Target Group Attachment ID is set") } - target := types.Target{ - Id: aws.String(targetID), - } + var err error + var port int + if v, ok := rs.Primary.Attributes["targets.0.port"]; ok { + port, err = strconv.Atoi(v) - if hasValidPort { - portStr := rs.Primary.Attributes["targets.0.port"] - port, err := strconv.Atoi(portStr) if err != nil { - return fmt.Errorf("Error parsing target port: %s", err) + return err } - target.Port = aws.Int32(int32(port)) } conn := acctest.Provider.Meta().(*conns.AWSClient).VPCLatticeClient() - resp, err := conn.ListTargets(ctx, &vpclattice.ListTargetsInput{ - TargetGroupIdentifier: aws.String(targetGroupIdentifier), - Targets: []types.Target{target}, - }) - if err != nil { - return create.Error(names.VPCLattice, create.ErrActionCheckingExistence, tfvpclattice.ResNameRegisterTargets, rs.Primary.ID, err) - } - - *targets = *resp + _, err = tfvpclattice.FindTargetByThreePartKey(ctx, conn, rs.Primary.Attributes["target_group_identifier"], rs.Primary.Attributes["targets.0.id"], port) - return nil + return err } } @@ -450,39 +411,27 @@ func testAccCheckRegisterTargetsDestroy(ctx context.Context) resource.TestCheckF continue } - targetGroupIdentifier := rs.Primary.Attributes["target_group_identifier"] - targetID := rs.Primary.Attributes["targets.0.id"] - portStr, hasPort := rs.Primary.Attributes["targets.0.port"] - port, _ := strconv.Atoi(portStr) - hasValidPort := hasPort && port > 0 + var err error + var port int + if v, ok := rs.Primary.Attributes["targets.0.port"]; ok { + port, err = strconv.Atoi(v) - target := types.Target{ - Id: aws.String(targetID), - } - - if hasValidPort { - portStr := rs.Primary.Attributes["targets.0.port"] - port, err := strconv.Atoi(portStr) if err != nil { - return fmt.Errorf("Error parsing target port: %s", err) + return err } - target.Port = aws.Int32(int32(port)) } - _, err := conn.ListTargets(ctx, &vpclattice.ListTargetsInput{ - TargetGroupIdentifier: aws.String(targetGroupIdentifier), - Targets: []types.Target{target}, - }) + _, err = tfvpclattice.FindTargetByThreePartKey(ctx, conn, rs.Primary.Attributes["target_group_identifier"], rs.Primary.Attributes["targets.0.id"], port) + + if tfresource.NotFound(err) { + continue + } if err != nil { - var nfe *types.ResourceNotFoundException - if errors.As(err, &nfe) { - return nil - } return err } - return create.Error(names.VPCLattice, create.ErrActionCheckingDestroyed, tfvpclattice.ResNameRegisterTargets, rs.Primary.ID, errors.New("not destroyed")) + return fmt.Errorf("VPC Lattice Target Group Attachment %s still exists", rs.Primary.ID) } return nil diff --git a/website/docs/r/vpclattice_register_targets.html.markdown b/website/docs/r/vpclattice_target_group_attachment.html.markdown similarity index 63% rename from website/docs/r/vpclattice_register_targets.html.markdown rename to website/docs/r/vpclattice_target_group_attachment.html.markdown index 9df4f13f8e05..4f4aaf9425fe 100644 --- a/website/docs/r/vpclattice_register_targets.html.markdown +++ b/website/docs/r/vpclattice_target_group_attachment.html.markdown @@ -1,25 +1,24 @@ --- subcategory: "VPC Lattice" layout: "aws" -page_title: "AWS: aws_vpclattice_register_targets" +page_title: "AWS: aws_vpclattice_target_group_attachment" description: |- - Terraform resource for managing an AWS VPC Lattice Register Targets. + Provides the ability to register a target with an AWS VPC Lattice Target Group. --- -# Resource: aws_vpclattice_register_targets +# Resource: aws_vpclattice_target_group_attachment -Terraform resource for managing an AWS VPC Lattice Register Targets. +Provides the ability to register a target with an AWS VPC Lattice Target Group. ## Example Usage ### Basic Usage ```terraform -resource "aws_vpclattice_register_targets" "example" { - +resource "aws_vpclattice_target_group_attachment" "example" { target_group_identifier = aws_vpclattice_target_group.example.id - targets { + target { id = aws_lb.example.arn port = 80 } @@ -31,16 +30,13 @@ resource "aws_vpclattice_register_targets" "example" { The following arguments are required: - `target_group_identifier` - (Required) The ID or Amazon Resource Name (ARN) of the target group. -- `targets` - (Required) The target. +- `target` - (Required) The target. -targets (`targets`) supports the following: +`target` supports the following: - `id` - (Required) The ID of the target. If the target type of the target group is INSTANCE, this is an instance ID. If the target type is IP , this is an IP address. If the target type is LAMBDA, this is the ARN of the Lambda function. If the target type is ALB, this is the ARN of the Application Load Balancer. - - `port` - (Optional) The port on which the target is listening. For HTTP, the default is 80. For HTTPS, the default is 443. ## Attributes Reference -In addition to all arguments above, the following attributes are exported: - -- `id` - id of the target register. +No additional attributes are exported. From d2df152dfd108022e26eb54dff57178f89cdf669 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 2 May 2023 11:24:30 -0400 Subject: [PATCH 13/17] r/aws_vpclattice_target_group_attachment: Correct 'TestAccVPCLatticeTargetGroupAttachment_instance'. Acceptance test output: % make testacc TESTARGS='-run=TestAccVPCLatticeTargetGroupAttachment_instance' PKG=vpclattice ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/vpclattice/... -v -count 1 -parallel 20 -run=TestAccVPCLatticeTargetGroupAttachment_instance -timeout 180m === RUN TestAccVPCLatticeTargetGroupAttachment_instance === PAUSE TestAccVPCLatticeTargetGroupAttachment_instance === CONT TestAccVPCLatticeTargetGroupAttachment_instance --- PASS: TestAccVPCLatticeTargetGroupAttachment_instance (137.07s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/vpclattice 143.011s --- .../vpclattice/target_group_attachment.go | 1 + .../target_group_attachment_test.go | 62 ++++++------------- 2 files changed, 19 insertions(+), 44 deletions(-) diff --git a/internal/service/vpclattice/target_group_attachment.go b/internal/service/vpclattice/target_group_attachment.go index 1ba35715e5d5..e38b49d14814 100644 --- a/internal/service/vpclattice/target_group_attachment.go +++ b/internal/service/vpclattice/target_group_attachment.go @@ -51,6 +51,7 @@ func resourceTargetGroupAttachment() *schema.Resource { "port": { Type: schema.TypeInt, Optional: true, + Computed: true, ForceNew: true, ValidateFunc: validation.IsPortNumber, }, diff --git a/internal/service/vpclattice/target_group_attachment_test.go b/internal/service/vpclattice/target_group_attachment_test.go index 8698f0297e9c..69350c7f9eb1 100644 --- a/internal/service/vpclattice/target_group_attachment_test.go +++ b/internal/service/vpclattice/target_group_attachment_test.go @@ -19,8 +19,8 @@ import ( func TestAccVPCLatticeTargetGroupAttachment_instance(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_vpclattice_register_targets.test" - instanceId := "aws_instance.test_instance" + resourceName := "aws_vpclattice_target_group_attachment.test" + instanceResourceName := "aws_instance.test" targetGroupResourceName := "aws_vpclattice_target_group.test" resource.ParallelTest(t, resource.TestCase{ @@ -34,12 +34,12 @@ func TestAccVPCLatticeTargetGroupAttachment_instance(t *testing.T) { CheckDestroy: testAccCheckRegisterTargetsDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccRegisterTargets_instance(rName), + Config: testAccRegisterTargetsConfig_instance(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTargetsExists(ctx, resourceName), resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, "target_group_identifier"), - resource.TestCheckResourceAttrPair(resourceName, "targets.0.id", instanceId, "id"), - resource.TestCheckResourceAttr(resourceName, "targets.0.port", "80"), + resource.TestCheckResourceAttrPair(resourceName, "target.0.id", instanceResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "target.0.port", "80"), ), }, }, @@ -145,34 +145,16 @@ func TestAccVPCLatticeTargetGroupAttachment_alb(t *testing.T) { } func testAccRegisterTargetsConfig_instance(rName string) string { - return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 1), fmt.Sprintf(` - - -data "aws_ami" "amzn-ami-minimal-hvm-ebs" { - most_recent = true - owners = ["amazon"] - - filter { - name = "name" - values = ["amzn-ami-minimal-hvm-*"] - } - - filter { - name = "root-device-type" - values = ["ebs"] - } -} - -resource "aws_instance" "test_instance" { + return acctest.ConfigCompose(acctest.ConfigLatestAmazonLinuxHVMEBSAMI(), acctest.ConfigVPCWithSubnets(rName, 1), fmt.Sprintf(` +resource "aws_instance" "test" { ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id - instance_type = "t3.large" + instance_type = "t2.small" subnet_id = aws_subnet.test[0].id } resource "aws_vpclattice_target_group" "test" { - depends_on = [aws_instance.test_instance] - name = %[1]q - type = "INSTANCE" + name = %[1]q + type = "INSTANCE" config { port = 80 @@ -180,23 +162,15 @@ resource "aws_vpclattice_target_group" "test" { vpc_identifier = aws_vpc.test.id } } -`, rName)) -} -func testAccRegisterTargets_instance(rName string) string { - return acctest.ConfigCompose(testAccRegisterTargetsConfig_instance(rName), ` -resource "aws_vpclattice_register_targets" "test" { - depends_on = [aws_vpclattice_target_group.test] +resource "aws_vpclattice_target_group_attachment" "test" { target_group_identifier = aws_vpclattice_target_group.test.id - targets { - id = aws_instance.test_instance.id - port = 80 + target { + id = aws_instance.test.id } } - - -`) +`, rName)) } func testAccRegisterTargetsConfig_ipAddress(rName string) string { @@ -386,7 +360,7 @@ func testAccCheckTargetsExists(ctx context.Context, n string) resource.TestCheck var err error var port int - if v, ok := rs.Primary.Attributes["targets.0.port"]; ok { + if v, ok := rs.Primary.Attributes["target.0.port"]; ok { port, err = strconv.Atoi(v) if err != nil { @@ -396,7 +370,7 @@ func testAccCheckTargetsExists(ctx context.Context, n string) resource.TestCheck conn := acctest.Provider.Meta().(*conns.AWSClient).VPCLatticeClient() - _, err = tfvpclattice.FindTargetByThreePartKey(ctx, conn, rs.Primary.Attributes["target_group_identifier"], rs.Primary.Attributes["targets.0.id"], port) + _, err = tfvpclattice.FindTargetByThreePartKey(ctx, conn, rs.Primary.Attributes["target_group_identifier"], rs.Primary.Attributes["target.0.id"], port) return err } @@ -413,7 +387,7 @@ func testAccCheckRegisterTargetsDestroy(ctx context.Context) resource.TestCheckF var err error var port int - if v, ok := rs.Primary.Attributes["targets.0.port"]; ok { + if v, ok := rs.Primary.Attributes["target.0.port"]; ok { port, err = strconv.Atoi(v) if err != nil { @@ -421,7 +395,7 @@ func testAccCheckRegisterTargetsDestroy(ctx context.Context) resource.TestCheckF } } - _, err = tfvpclattice.FindTargetByThreePartKey(ctx, conn, rs.Primary.Attributes["target_group_identifier"], rs.Primary.Attributes["targets.0.id"], port) + _, err = tfvpclattice.FindTargetByThreePartKey(ctx, conn, rs.Primary.Attributes["target_group_identifier"], rs.Primary.Attributes["target.0.id"], port) if tfresource.NotFound(err) { continue From 876666767a5c180787f4a7d33b72d2c250ca0296 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 2 May 2023 11:50:20 -0400 Subject: [PATCH 14/17] r/aws_vpclattice_target_group_attachment: Correct 'TestAccVPCLatticeTargetGroupAttachment_ip'. Acceptance test output: % make testacc TESTARGS='-run=TestAccVPCLatticeTargetGroupAttachment_ip' PKG=vpclattice ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/vpclattice/... -v -count 1 -parallel 20 -run=TestAccVPCLatticeTargetGroupAttachment_ip -timeout 180m === RUN TestAccVPCLatticeTargetGroupAttachment_ip === PAUSE TestAccVPCLatticeTargetGroupAttachment_ip === CONT TestAccVPCLatticeTargetGroupAttachment_ip --- PASS: TestAccVPCLatticeTargetGroupAttachment_ip (106.60s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/vpclattice 111.940s --- .../target_group_attachment_test.go | 79 ++++++------------- 1 file changed, 26 insertions(+), 53 deletions(-) diff --git a/internal/service/vpclattice/target_group_attachment_test.go b/internal/service/vpclattice/target_group_attachment_test.go index 69350c7f9eb1..16a80b30f572 100644 --- a/internal/service/vpclattice/target_group_attachment_test.go +++ b/internal/service/vpclattice/target_group_attachment_test.go @@ -21,7 +21,6 @@ func TestAccVPCLatticeTargetGroupAttachment_instance(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_vpclattice_target_group_attachment.test" instanceResourceName := "aws_instance.test" - targetGroupResourceName := "aws_vpclattice_target_group.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { @@ -34,10 +33,10 @@ func TestAccVPCLatticeTargetGroupAttachment_instance(t *testing.T) { CheckDestroy: testAccCheckRegisterTargetsDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccRegisterTargetsConfig_instance(rName), + Config: testAccTargetGroupAttachmentConfig_instance(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTargetsExists(ctx, resourceName), - resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, "target_group_identifier"), + resource.TestCheckResourceAttr(resourceName, "target.#", "1"), resource.TestCheckResourceAttrPair(resourceName, "target.0.id", instanceResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "target.0.port", "80"), ), @@ -49,9 +48,8 @@ func TestAccVPCLatticeTargetGroupAttachment_instance(t *testing.T) { func TestAccVPCLatticeTargetGroupAttachment_ip(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_vpclattice_register_targets.test" - instanceIP := "aws_instance.test_ip" - targetGroupResourceName := "aws_vpclattice_target_group.test" + resourceName := "aws_vpclattice_target_group_attachment.test" + instanceResourceName := "aws_instance.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { @@ -64,12 +62,12 @@ func TestAccVPCLatticeTargetGroupAttachment_ip(t *testing.T) { CheckDestroy: testAccCheckRegisterTargetsDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccRegisterTargets_ip(rName), + Config: testAccTargetGroupAttachmentConfig_ip(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTargetsExists(ctx, resourceName), - resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, "target_group_identifier"), - resource.TestCheckResourceAttrPair(resourceName, "targets.0.id", instanceIP, "private_ip"), - resource.TestCheckResourceAttr(resourceName, "targets.0.port", "80"), + resource.TestCheckResourceAttr(resourceName, "target.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "target.0.id", instanceResourceName, "private_ip"), + resource.TestCheckResourceAttr(resourceName, "target.0.port", "8080"), ), }, }, @@ -144,14 +142,22 @@ func TestAccVPCLatticeTargetGroupAttachment_alb(t *testing.T) { }) } -func testAccRegisterTargetsConfig_instance(rName string) string { +func testAccTargetGroupAttachmentConfig_baseInstance(rName string) string { return acctest.ConfigCompose(acctest.ConfigLatestAmazonLinuxHVMEBSAMI(), acctest.ConfigVPCWithSubnets(rName, 1), fmt.Sprintf(` resource "aws_instance" "test" { ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id instance_type = "t2.small" subnet_id = aws_subnet.test[0].id + + tags = { + Name = %[1]q + } +} +`, rName)) } +func testAccTargetGroupAttachmentConfig_instance(rName string) string { + return acctest.ConfigCompose(testAccTargetGroupAttachmentConfig_baseInstance(rName), fmt.Sprintf(` resource "aws_vpclattice_target_group" "test" { name = %[1]q type = "INSTANCE" @@ -173,35 +179,11 @@ resource "aws_vpclattice_target_group_attachment" "test" { `, rName)) } -func testAccRegisterTargetsConfig_ipAddress(rName string) string { - return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 1), fmt.Sprintf(` - - -data "aws_ami" "amzn-ami-minimal-hvm-ebs" { - most_recent = true - owners = ["amazon"] - - filter { - name = "name" - values = ["amzn-ami-minimal-hvm-*"] - } - - filter { - name = "root-device-type" - values = ["ebs"] - } -} - -resource "aws_instance" "test_ip" { - ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id - instance_type = "t3.large" - subnet_id = aws_subnet.test[0].id -} - +func testAccTargetGroupAttachmentConfig_ip(rName string) string { + return acctest.ConfigCompose(testAccTargetGroupAttachmentConfig_baseInstance(rName), fmt.Sprintf(` resource "aws_vpclattice_target_group" "test" { - depends_on = [aws_instance.test_ip] - name = %[1]q - type = "IP" + name = %[1]q + type = "IP" config { port = 80 @@ -209,25 +191,16 @@ resource "aws_vpclattice_target_group" "test" { vpc_identifier = aws_vpc.test.id } } -`, rName)) -} - -func testAccRegisterTargets_ip(rName string) string { - return acctest.ConfigCompose(testAccRegisterTargetsConfig_ipAddress(rName), ` - -resource "aws_vpclattice_register_targets" "test" { - depends_on = [aws_vpclattice_target_group.test] +resource "aws_vpclattice_target_group_attachment" "test" { target_group_identifier = aws_vpclattice_target_group.test.id - targets { - id = aws_instance.test_ip.private_ip - port = 80 + target { + id = aws_instance.test.private_ip + port = 8080 } } - - -`) +`, rName)) } func testAccRegisterTargetsConfig_lambda(rName string) string { From 326beaa67c7c70bb5a81db4c23eca1e3905f8411 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 2 May 2023 12:28:49 -0400 Subject: [PATCH 15/17] r/aws_vpclattice_target_group_attachment: Correct 'TestAccVPCLatticeTargetGroupAttachment_lambda'. Acceptance test output: % make testacc TESTARGS='-run=TestAccVPCLatticeTargetGroupAttachment_lambda' PKG=vpclattice ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/vpclattice/... -v -count 1 -parallel 20 -run=TestAccVPCLatticeTargetGroupAttachment_lambda -timeout 180m === RUN TestAccVPCLatticeTargetGroupAttachment_lambda === PAUSE TestAccVPCLatticeTargetGroupAttachment_lambda === CONT TestAccVPCLatticeTargetGroupAttachment_lambda --- PASS: TestAccVPCLatticeTargetGroupAttachment_lambda (38.79s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/vpclattice 43.988s --- .../target_group_attachment_test.go | 65 +++++++------------ 1 file changed, 24 insertions(+), 41 deletions(-) diff --git a/internal/service/vpclattice/target_group_attachment_test.go b/internal/service/vpclattice/target_group_attachment_test.go index 16a80b30f572..49b2bd235624 100644 --- a/internal/service/vpclattice/target_group_attachment_test.go +++ b/internal/service/vpclattice/target_group_attachment_test.go @@ -77,9 +77,8 @@ func TestAccVPCLatticeTargetGroupAttachment_ip(t *testing.T) { func TestAccVPCLatticeTargetGroupAttachment_lambda(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_vpclattice_register_targets.test" - lambdaName := "aws_lambda_function.test" - targetGroupResourceName := "aws_vpclattice_target_group.test" + resourceName := "aws_vpclattice_target_group_attachment.test" + lambdaResourceName := "aws_lambda_function.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { @@ -92,18 +91,14 @@ func TestAccVPCLatticeTargetGroupAttachment_lambda(t *testing.T) { CheckDestroy: testAccCheckRegisterTargetsDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccRegisterTargets_lambda(rName), + Config: testAccTargetGroupAttachmentConfig_lambda(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTargetsExists(ctx, resourceName), - resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, "target_group_identifier"), - resource.TestCheckResourceAttrPair(resourceName, "targets.0.id", lambdaName, "arn"), + resource.TestCheckResourceAttr(resourceName, "target.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "target.0.id", lambdaResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "target.0.port", "0"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, }, }) } @@ -203,61 +198,49 @@ resource "aws_vpclattice_target_group_attachment" "test" { `, rName)) } -func testAccRegisterTargetsConfig_lambda(rName string) string { +func testAccTargetGroupAttachmentConfig_lambda(rName string) string { return fmt.Sprintf(` data "aws_partition" "current" {} resource "aws_vpclattice_target_group" "test" { - depends_on = [aws_lambda_function.test] - name = %[1]q - type = "LAMBDA" - + name = %[1]q + type = "LAMBDA" } resource "aws_lambda_function" "test" { filename = "test-fixtures/lambda.zip" function_name = %[1]q role = aws_iam_role.test.arn - handler = "lambda_elb.lambda_handler" + handler = "test.handler" runtime = "python3.7" } - - resource "aws_iam_role" "test" { + name = %[1]q + assume_role_policy = < Date: Tue, 2 May 2023 13:29:17 -0400 Subject: [PATCH 16/17] r/aws_vpclattice_target_group_attachment: Correct 'TestAccVPCLatticeTargetGroupAttachment_alb'. Acceptance test output: % make testacc TESTARGS='-run=TestAccVPCLatticeTargetGroupAttachment_alb' PKG=vpclattice ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/vpclattice/... -v -count 1 -parallel 20 -run=TestAccVPCLatticeTargetGroupAttachment_alb -timeout 180m === RUN TestAccVPCLatticeTargetGroupAttachment_alb === PAUSE TestAccVPCLatticeTargetGroupAttachment_alb === CONT TestAccVPCLatticeTargetGroupAttachment_alb --- PASS: TestAccVPCLatticeTargetGroupAttachment_alb (171.26s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/vpclattice 176.815s --- .../target_group_attachment_test.go | 40 ++++++------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/internal/service/vpclattice/target_group_attachment_test.go b/internal/service/vpclattice/target_group_attachment_test.go index 49b2bd235624..9f1b949311b8 100644 --- a/internal/service/vpclattice/target_group_attachment_test.go +++ b/internal/service/vpclattice/target_group_attachment_test.go @@ -106,9 +106,8 @@ func TestAccVPCLatticeTargetGroupAttachment_lambda(t *testing.T) { func TestAccVPCLatticeTargetGroupAttachment_alb(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_vpclattice_register_targets.test" - albName := "aws_lb.test" - targetGroupResourceName := "aws_vpclattice_target_group.test" + resourceName := "aws_vpclattice_target_group_attachment.test" + albResourceName := "aws_lb.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { @@ -121,18 +120,14 @@ func TestAccVPCLatticeTargetGroupAttachment_alb(t *testing.T) { CheckDestroy: testAccCheckRegisterTargetsDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccRegisterTargets_alb(rName), + Config: testAccTargetGroupAttachmentConfig_alb(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTargetsExists(ctx, resourceName), - resource.TestCheckResourceAttrPair(resourceName, "default_action.0.forward.0.target_groups.0.target_group_identifier", targetGroupResourceName, "target_group_identifier"), - resource.TestCheckResourceAttrPair(resourceName, "targets.0.id", albName, "arn"), + resource.TestCheckResourceAttr(resourceName, "target.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "target.0.id", albResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "target.0.port", "80"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, }, }) } @@ -243,10 +238,8 @@ resource "aws_vpclattice_target_group_attachment" "test" { `, rName) } -func testAccRegisterTargetsConfig_alb(rName string) string { +func testAccTargetGroupAttachmentConfig_alb(rName string) string { return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 2), fmt.Sprintf(` - - resource "aws_vpclattice_target_group" "test" { name = %[1]q type = "ALB" @@ -262,16 +255,16 @@ resource "aws_lb" "test" { name = %[1]q internal = true load_balancer_type = "application" - subnets = [aws_subnet.test[0].id, aws_subnet.test[1].id] + subnets = aws_subnet.test[*].id enable_deletion_protection = false - } resource "aws_lb_listener" "test" { load_balancer_arn = aws_lb.test.arn port = "80" protocol = "HTTP" + default_action { type = "fixed-response" @@ -283,24 +276,15 @@ resource "aws_lb_listener" "test" { } } - -`, rName)) -} - -func testAccRegisterTargets_alb(rName string) string { - return acctest.ConfigCompose(testAccRegisterTargetsConfig_alb(rName), ` -resource "aws_vpclattice_register_targets" "test" { - depends_on = [aws_lb.test] +resource "aws_vpclattice_target_group_attachment" "test" { target_group_identifier = aws_vpclattice_target_group.test.id - targets { + target { id = aws_lb.test.arn port = 80 } } - - -`) +`, rName)) } func testAccCheckTargetsExists(ctx context.Context, n string) resource.TestCheckFunc { From e9417e8c9b153d94b761384faea4c1dd22118aa1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 2 May 2023 13:35:35 -0400 Subject: [PATCH 17/17] r/aws_vpclattice_target_group_attachment: Add 'TestAccVPCLatticeTargetGroupAttachment_disappears'. Acceptance test output: % make testacc TESTARGS='-run=TestAccVPCLatticeTargetGroupAttachment_disappears' PKG=vpclattice ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/vpclattice/... -v -count 1 -parallel 20 -run=TestAccVPCLatticeTargetGroupAttachment_disappears -timeout 180m === RUN TestAccVPCLatticeTargetGroupAttachment_disappears === PAUSE TestAccVPCLatticeTargetGroupAttachment_disappears === CONT TestAccVPCLatticeTargetGroupAttachment_disappears --- PASS: TestAccVPCLatticeTargetGroupAttachment_disappears (117.02s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/vpclattice 122.966s --- .../target_group_attachment_test.go | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/internal/service/vpclattice/target_group_attachment_test.go b/internal/service/vpclattice/target_group_attachment_test.go index 9f1b949311b8..537b56ee330a 100644 --- a/internal/service/vpclattice/target_group_attachment_test.go +++ b/internal/service/vpclattice/target_group_attachment_test.go @@ -132,6 +132,32 @@ func TestAccVPCLatticeTargetGroupAttachment_alb(t *testing.T) { }) } +func TestAccVPCLatticeTargetGroupAttachment_disappears(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_vpclattice_target_group_attachment.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: testAccCheckRegisterTargetsDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTargetGroupAttachmentConfig_instance(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckTargetsExists(ctx, resourceName), + acctest.CheckResourceDisappears(ctx, acctest.Provider, tfvpclattice.ResourceTargetGroupAttachment(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccTargetGroupAttachmentConfig_baseInstance(rName string) string { return acctest.ConfigCompose(acctest.ConfigLatestAmazonLinuxHVMEBSAMI(), acctest.ConfigVPCWithSubnets(rName, 1), fmt.Sprintf(` resource "aws_instance" "test" {