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 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..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) } @@ -184,7 +194,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()) @@ -214,7 +224,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) } @@ -242,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") { @@ -271,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 @@ -301,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/project_test.go b/internal/service/evidently/project_test.go index 7d521dd2fd2..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"), ), @@ -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" @@ -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 diff --git a/internal/service/evidently/status.go b/internal/service/evidently/status.go new file mode 100644 index 00000000000..ad2ccabec62 --- /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/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 tfresource.NotFound(err) { + return nil, "", 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..a763303084c --- /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.Project, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{}, + Target: []string{cloudwatchevidently.ProjectStatusAvailable}, + Refresh: statusProject(conn, nameOrARN), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*cloudwatchevidently.Project); ok { + return output, err + } + + return nil, err +} + +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}, + Refresh: statusProject(conn, nameOrARN), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*cloudwatchevidently.Project); ok { + return output, err + } + + return nil, err +} + +func waitProjectDeleted(conn *cloudwatchevidently.CloudWatchEvidently, nameOrARN string, timeout time.Duration) (*cloudwatchevidently.Project, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{cloudwatchevidently.ProjectStatusAvailable}, + Target: []string{}, + Refresh: statusProject(conn, nameOrARN), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*cloudwatchevidently.Project); 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: