From 560bd8143dcdfd165011cf4bb724cf5299cf4095 Mon Sep 17 00:00:00 2001 From: GlennChia Date: Wed, 19 Oct 2022 17:07:17 +0000 Subject: [PATCH 1/9] refactor(cwevi): find function uses name or arn --- internal/service/evidently/find.go | 4 ++-- internal/service/evidently/project.go | 2 +- internal/service/evidently/project_test.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/service/evidently/find.go b/internal/service/evidently/find.go index 441ae04be19..0f6b556f019 100644 --- a/internal/service/evidently/find.go +++ b/internal/service/evidently/find.go @@ -10,9 +10,9 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) -func FindProjectByName(ctx context.Context, conn *cloudwatchevidently.CloudWatchEvidently, name string) (*cloudwatchevidently.Project, error) { +func FindProjectByNameOrARN(ctx context.Context, conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN string) (*cloudwatchevidently.Project, error) { input := &cloudwatchevidently.GetProjectInput{ - Project: aws.String(name), + Project: aws.String(nameOrARN), } output, err := conn.GetProjectWithContext(ctx, input) diff --git a/internal/service/evidently/project.go b/internal/service/evidently/project.go index 565c198b1b5..eab15fa888e 100644 --- a/internal/service/evidently/project.go +++ b/internal/service/evidently/project.go @@ -184,7 +184,7 @@ func resourceProjectRead(ctx context.Context, d *schema.ResourceData, meta inter defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - project, err := FindProjectByName(ctx, conn, d.Id()) + project, err := FindProjectByNameOrARN(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] CloudWatch Evidently Project (%s) not found, removing from state", d.Id()) diff --git a/internal/service/evidently/project_test.go b/internal/service/evidently/project_test.go index 7d521dd2fd2..446c12b278d 100644 --- a/internal/service/evidently/project_test.go +++ b/internal/service/evidently/project_test.go @@ -357,7 +357,7 @@ func testAccCheckProjectDestroy(s *terraform.State) error { continue } - _, err := tfcloudwatchevidently.FindProjectByName(context.Background(), conn, rs.Primary.ID) + _, err := tfcloudwatchevidently.FindProjectByNameOrARN(context.Background(), conn, rs.Primary.ID) if tfresource.NotFound(err) { continue @@ -387,7 +387,7 @@ func testAccCheckProjectExists(n string, v *cloudwatchevidently.Project) resourc conn := acctest.Provider.Meta().(*conns.AWSClient).EvidentlyConn - output, err := tfcloudwatchevidently.FindProjectByName(context.Background(), conn, rs.Primary.ID) + output, err := tfcloudwatchevidently.FindProjectByNameOrARN(context.Background(), conn, rs.Primary.ID) if err != nil { return err From 0aa766f2a7e798b65f9cdbae867dd946a24b4f34 Mon Sep 17 00:00:00 2001 From: GlennChia Date: Wed, 19 Oct 2022 17:51:38 +0000 Subject: [PATCH 2/9] chore(cwevi): rm unused comment --- internal/service/evidently/project.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/service/evidently/project.go b/internal/service/evidently/project.go index eab15fa888e..eb38f8192c7 100644 --- a/internal/service/evidently/project.go +++ b/internal/service/evidently/project.go @@ -214,7 +214,6 @@ func resourceProjectRead(ctx context.Context, d *schema.ResourceData, meta inter tags := KeyValueTags(project.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig) - //lintignore:AWSR002 if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { return diag.Errorf("setting tags: %s", err) } From 7c4a6683ac22fbf4afe18438765b81e9ca316a67 Mon Sep 17 00:00:00 2001 From: GlennChia Date: Wed, 19 Oct 2022 19:17:14 +0000 Subject: [PATCH 3/9] feat(cwevi): project waiters --- internal/service/evidently/project.go | 30 ++++++++-- internal/service/evidently/status.go | 26 ++++++++ internal/service/evidently/wait.go | 59 +++++++++++++++++++ .../docs/r/evidently_project.html.markdown | 8 +++ 4 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 internal/service/evidently/status.go create mode 100644 internal/service/evidently/wait.go diff --git a/internal/service/evidently/project.go b/internal/service/evidently/project.go index eb38f8192c7..7061cec1b32 100644 --- a/internal/service/evidently/project.go +++ b/internal/service/evidently/project.go @@ -20,15 +20,21 @@ import ( func ResourceProject() *schema.Resource { return &schema.Resource{ - CreateWithoutTimeout: resourceProjectCreate, - ReadWithoutTimeout: resourceProjectRead, - UpdateWithoutTimeout: resourceProjectUpdate, - DeleteWithoutTimeout: resourceProjectDelete, + CreateContext: resourceProjectCreate, + ReadContext: resourceProjectRead, + UpdateContext: resourceProjectUpdate, + DeleteContext: resourceProjectDelete, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(2 * time.Minute), + Update: schema.DefaultTimeout(2 * time.Minute), + Delete: schema.DefaultTimeout(2 * time.Minute), + }, + Schema: map[string]*schema.Schema{ "active_experiment_count": { Type: schema.TypeInt, @@ -176,6 +182,10 @@ func resourceProjectCreate(ctx context.Context, d *schema.ResourceData, meta int d.SetId(aws.StringValue(output.Project.Name)) + if _, err := waitProjectCreated(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return diag.Errorf("waiting for CloudWatch Evidently Project (%s) creation: %s", d.Id(), err) + } + return resourceProjectRead(ctx, d, meta) } @@ -241,6 +251,10 @@ func resourceProjectUpdate(ctx context.Context, d *schema.ResourceData, meta int if err != nil { return diag.Errorf("updating CloudWatch Evidently Project (%s): %s", d.Id(), err) } + + if _, err := waitProjectUpdated(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { + return diag.Errorf("waiting for CloudWatch Evidently Project (%s) update: %s", d.Id(), err) + } } if d.HasChange("data_delivery") { @@ -270,6 +284,10 @@ func resourceProjectUpdate(ctx context.Context, d *schema.ResourceData, meta int if err != nil { return diag.Errorf("updating CloudWatch Evidently Project (%s) data delivery: %s", d.Id(), err) } + + if _, err := waitProjectUpdated(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { + return diag.Errorf("waiting for CloudWatch Evidently Project (%s) update: %s", d.Id(), err) + } } // updates to tags @@ -300,6 +318,10 @@ func resourceProjectDelete(ctx context.Context, d *schema.ResourceData, meta int return diag.Errorf("deleting CloudWatch Evidently Project (%s): %s", d.Id(), err) } + if _, err := waitProjectDeleted(conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { + return diag.Errorf("waiting for CloudWatch Evidently Project (%s) deletion: %s", d.Id(), err) + } + return nil } diff --git a/internal/service/evidently/status.go b/internal/service/evidently/status.go new file mode 100644 index 00000000000..c537b88b5ff --- /dev/null +++ b/internal/service/evidently/status.go @@ -0,0 +1,26 @@ +package evidently + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/cloudwatchevidently" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func statusProject(conn *cloudwatchevidently.CloudWatchEvidently, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := FindProjectByNameOrARN(context.Background(), conn, id) + + if tfawserr.ErrCodeEquals(err, cloudwatchevidently.ErrCodeResourceNotFoundException) { + return output, cloudwatchevidently.ErrCodeResourceNotFoundException, nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.Status), nil + } +} diff --git a/internal/service/evidently/wait.go b/internal/service/evidently/wait.go new file mode 100644 index 00000000000..f5e8c2ceca6 --- /dev/null +++ b/internal/service/evidently/wait.go @@ -0,0 +1,59 @@ +package evidently + +import ( + "time" + + "github.com/aws/aws-sdk-go/service/cloudwatchevidently" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func waitProjectCreated(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN string, timeout time.Duration) (*cloudwatchevidently.GetProjectOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{}, + Target: []string{cloudwatchevidently.ProjectStatusAvailable}, + Refresh: statusProject(conn, nameOrARN), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*cloudwatchevidently.GetProjectOutput); ok { + return v, err + } + + return nil, err +} + +func waitProjectUpdated(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN string, timeout time.Duration) (*cloudwatchevidently.GetProjectOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{cloudwatchevidently.ProjectStatusUpdating}, + Target: []string{cloudwatchevidently.ProjectStatusAvailable}, + Refresh: statusProject(conn, nameOrARN), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*cloudwatchevidently.GetProjectOutput); ok { + return v, err + } + + return nil, err +} + +func waitProjectDeleted(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN string, timeout time.Duration) (*cloudwatchevidently.GetProjectOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{cloudwatchevidently.ProjectStatusAvailable}, + Target: []string{cloudwatchevidently.ErrCodeResourceNotFoundException}, + Refresh: statusProject(conn, nameOrARN), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*cloudwatchevidently.GetProjectOutput); ok { + return output, err + } + + return nil, err +} diff --git a/website/docs/r/evidently_project.html.markdown b/website/docs/r/evidently_project.html.markdown index 3877c305fc2..35bff978c26 100644 --- a/website/docs/r/evidently_project.html.markdown +++ b/website/docs/r/evidently_project.html.markdown @@ -89,6 +89,14 @@ The `s3_destination` block supports the following arguments: * `bucket` - (Optional) The name of the bucket in which Evidently stores evaluation events. * `prefix` - (Optional) The bucket prefix in which Evidently stores evaluation events. +## Timeouts + +[Configuration options](https://www.terraform.io/docs/configuration/blocks/resources/syntax.html#operation-timeouts): + +* `create` - (Default `2m`) +* `delete` - (Default `2m`) +* `update` - (Default `2m`) + ## Attributes Reference In addition to all arguments above, the following attributes are exported: From d87fb96382f7d5be21df1f67e24f710397db0240 Mon Sep 17 00:00:00 2001 From: GlennChia Date: Thu, 20 Oct 2022 03:15:25 +0000 Subject: [PATCH 4/9] ci(cwevi): changelog project timeouts --- .changelog/27336.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/27336.txt diff --git a/.changelog/27336.txt b/.changelog/27336.txt new file mode 100644 index 00000000000..8050afb645a --- /dev/null +++ b/.changelog/27336.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_evidently_project: Support configurable timeouts for create, update, and delete +``` \ No newline at end of file From a6c35b4055cee48b1124801f80112769c98ec1dd Mon Sep 17 00:00:00 2001 From: GlennChia Date: Thu, 20 Oct 2022 03:22:18 +0000 Subject: [PATCH 5/9] test(cwevi): fix log grp name to /aws/vendedlogs --- internal/service/evidently/project_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/evidently/project_test.go b/internal/service/evidently/project_test.go index 446c12b278d..bff333c71fb 100644 --- a/internal/service/evidently/project_test.go +++ b/internal/service/evidently/project_test.go @@ -140,8 +140,8 @@ func TestAccEvidentlyProject_updateDataDeliveryCloudWatchLogGroup(t *testing.T) rName := sdkacctest.RandomWithPrefix("tf-test-bucket") rName2 := sdkacctest.RandomWithPrefix("tf-test-bucket") - rName3 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - rName4 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName3 := sdkacctest.RandomWithPrefix(fmt.Sprintf("/aws/vendedlogs/%s", acctest.ResourcePrefix)) + rName4 := sdkacctest.RandomWithPrefix(fmt.Sprintf("/aws/vendedlogs/%s", acctest.ResourcePrefix)) rName5 := sdkacctest.RandomWithPrefix("resource-test-terraform") resourceName := "aws_evidently_project.test" @@ -283,8 +283,8 @@ func TestAccEvidentlyProject_updateDataDeliveryCloudWatchToS3(t *testing.T) { rName := sdkacctest.RandomWithPrefix("tf-test-bucket") rName2 := sdkacctest.RandomWithPrefix("tf-test-bucket") - rName3 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - rName4 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName3 := sdkacctest.RandomWithPrefix(fmt.Sprintf("/aws/vendedlogs/%s", acctest.ResourcePrefix)) + rName4 := sdkacctest.RandomWithPrefix(fmt.Sprintf("/aws/vendedlogs/%s", acctest.ResourcePrefix)) rName5 := sdkacctest.RandomWithPrefix("resource-test-terraform") resourceName := "aws_evidently_project.test" prefix := "tests3prefix" From f86ff568626588c323840e3bd9002a4fae4a6a5a Mon Sep 17 00:00:00 2001 From: GlennChia Date: Thu, 20 Oct 2022 03:35:25 +0000 Subject: [PATCH 6/9] refactor(cwevi): rename v to output --- internal/service/evidently/wait.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/evidently/wait.go b/internal/service/evidently/wait.go index f5e8c2ceca6..4c7f1633fa1 100644 --- a/internal/service/evidently/wait.go +++ b/internal/service/evidently/wait.go @@ -17,8 +17,8 @@ func waitProjectCreated(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN outputRaw, err := stateConf.WaitForState() - if v, ok := outputRaw.(*cloudwatchevidently.GetProjectOutput); ok { - return v, err + if output, ok := outputRaw.(*cloudwatchevidently.GetProjectOutput); ok { + return output, err } return nil, err @@ -34,8 +34,8 @@ func waitProjectUpdated(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN outputRaw, err := stateConf.WaitForState() - if v, ok := outputRaw.(*cloudwatchevidently.GetProjectOutput); ok { - return v, err + if output, ok := outputRaw.(*cloudwatchevidently.GetProjectOutput); ok { + return output, err } return nil, err From cd7d5c7135435e9b1cc1e5022449269cfd674663 Mon Sep 17 00:00:00 2001 From: GlennChia Date: Thu, 20 Oct 2022 16:03:04 +0000 Subject: [PATCH 7/9] ci(cwevi): nolint unparam update waiter --- internal/service/evidently/wait.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/evidently/wait.go b/internal/service/evidently/wait.go index 4c7f1633fa1..762b913fcb5 100644 --- a/internal/service/evidently/wait.go +++ b/internal/service/evidently/wait.go @@ -24,7 +24,7 @@ func waitProjectCreated(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN return nil, err } -func waitProjectUpdated(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN string, timeout time.Duration) (*cloudwatchevidently.GetProjectOutput, error) { +func waitProjectUpdated(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN string, timeout time.Duration) (*cloudwatchevidently.GetProjectOutput, error) { //nolint:unparam stateConf := &resource.StateChangeConf{ Pending: []string{cloudwatchevidently.ProjectStatusUpdating}, Target: []string{cloudwatchevidently.ProjectStatusAvailable}, From 9a078606fe6ffb5c89e275217d5fd951a9d21f7d Mon Sep 17 00:00:00 2001 From: GlennChia Date: Thu, 20 Oct 2022 17:28:24 +0000 Subject: [PATCH 8/9] test(cwevi): exact value of status --- internal/service/evidently/project_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/evidently/project_test.go b/internal/service/evidently/project_test.go index bff333c71fb..850b1d774c0 100644 --- a/internal/service/evidently/project_test.go +++ b/internal/service/evidently/project_test.go @@ -46,7 +46,7 @@ func TestAccEvidentlyProject_basic(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "last_updated_time"), resource.TestCheckResourceAttrSet(resourceName, "launch_count"), resource.TestCheckResourceAttr(resourceName, "name", rName), - resource.TestCheckResourceAttrSet(resourceName, "status"), + resource.TestCheckResourceAttr(resourceName, "status", cloudwatchevidently.ProjectStatusAvailable), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.Key1", "Test Project"), ), From d6fb21f6f558f4f4c8644839875c4f720de70419 Mon Sep 17 00:00:00 2001 From: Glenn Date: Sat, 22 Oct 2022 04:26:37 +0800 Subject: [PATCH 9/9] refactor(cwevi): type fixes, err handling in status Co-authored-by: Adrian Johnson --- internal/service/evidently/status.go | 6 +++--- internal/service/evidently/wait.go | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/service/evidently/status.go b/internal/service/evidently/status.go index c537b88b5ff..ad2ccabec62 100644 --- a/internal/service/evidently/status.go +++ b/internal/service/evidently/status.go @@ -5,16 +5,16 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/cloudwatchevidently" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func statusProject(conn *cloudwatchevidently.CloudWatchEvidently, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { output, err := FindProjectByNameOrARN(context.Background(), conn, id) - if tfawserr.ErrCodeEquals(err, cloudwatchevidently.ErrCodeResourceNotFoundException) { - return output, cloudwatchevidently.ErrCodeResourceNotFoundException, nil + if tfresource.NotFound(err) { + return nil, "", nil } if err != nil { diff --git a/internal/service/evidently/wait.go b/internal/service/evidently/wait.go index 762b913fcb5..a763303084c 100644 --- a/internal/service/evidently/wait.go +++ b/internal/service/evidently/wait.go @@ -7,7 +7,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -func waitProjectCreated(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN string, timeout time.Duration) (*cloudwatchevidently.GetProjectOutput, error) { +func waitProjectCreated(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN string, timeout time.Duration) (*cloudwatchevidently.Project, error) { stateConf := &resource.StateChangeConf{ Pending: []string{}, Target: []string{cloudwatchevidently.ProjectStatusAvailable}, @@ -17,14 +17,14 @@ func waitProjectCreated(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN outputRaw, err := stateConf.WaitForState() - if output, ok := outputRaw.(*cloudwatchevidently.GetProjectOutput); ok { + if output, ok := outputRaw.(*cloudwatchevidently.Project); ok { return output, err } return nil, err } -func waitProjectUpdated(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN string, timeout time.Duration) (*cloudwatchevidently.GetProjectOutput, error) { //nolint:unparam +func waitProjectUpdated(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN string, timeout time.Duration) (*cloudwatchevidently.Project, error) { //nolint:unparam stateConf := &resource.StateChangeConf{ Pending: []string{cloudwatchevidently.ProjectStatusUpdating}, Target: []string{cloudwatchevidently.ProjectStatusAvailable}, @@ -34,24 +34,24 @@ func waitProjectUpdated(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN outputRaw, err := stateConf.WaitForState() - if output, ok := outputRaw.(*cloudwatchevidently.GetProjectOutput); ok { + if output, ok := outputRaw.(*cloudwatchevidently.Project); ok { return output, err } return nil, err } -func waitProjectDeleted(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN string, timeout time.Duration) (*cloudwatchevidently.GetProjectOutput, error) { +func waitProjectDeleted(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN string, timeout time.Duration) (*cloudwatchevidently.Project, error) { stateConf := &resource.StateChangeConf{ Pending: []string{cloudwatchevidently.ProjectStatusAvailable}, - Target: []string{cloudwatchevidently.ErrCodeResourceNotFoundException}, + Target: []string{}, Refresh: statusProject(conn, nameOrARN), Timeout: timeout, } outputRaw, err := stateConf.WaitForState() - if output, ok := outputRaw.(*cloudwatchevidently.GetProjectOutput); ok { + if output, ok := outputRaw.(*cloudwatchevidently.Project); ok { return output, err }