From 988a04099b1bb7648e951f878e4a0f649904b2ab Mon Sep 17 00:00:00 2001 From: Andrew Babichev Date: Mon, 5 Oct 2020 11:49:57 +0300 Subject: [PATCH 1/2] Add configurable timeouts to workspaces --- .../service/workspaces/waiter/waiter.go | 12 ++--- aws/resource_aws_workspaces_workspace.go | 16 ++++-- aws/resource_aws_workspaces_workspace_test.go | 50 ++++++++++++++++++- .../docs/r/workspaces_workspace.html.markdown | 9 ++++ 4 files changed, 75 insertions(+), 12 deletions(-) diff --git a/aws/internal/service/workspaces/waiter/waiter.go b/aws/internal/service/workspaces/waiter/waiter.go index dfe535132fb..dadac13f2ff 100644 --- a/aws/internal/service/workspaces/waiter/waiter.go +++ b/aws/internal/service/workspaces/waiter/waiter.go @@ -69,7 +69,7 @@ func DirectoryDeregistered(conn *workspaces.WorkSpaces, directoryID string) (*wo return nil, err } -func WorkspaceAvailable(conn *workspaces.WorkSpaces, workspaceID string) (*workspaces.Workspace, error) { +func WorkspaceAvailable(conn *workspaces.WorkSpaces, workspaceID string, timeout time.Duration) (*workspaces.Workspace, error) { stateConf := &resource.StateChangeConf{ Pending: []string{ workspaces.WorkspaceStatePending, @@ -77,7 +77,7 @@ func WorkspaceAvailable(conn *workspaces.WorkSpaces, workspaceID string) (*works }, Target: []string{workspaces.WorkspaceStateAvailable}, Refresh: WorkspaceState(conn, workspaceID), - Timeout: WorkspaceAvailableTimeout, + Timeout: timeout, } outputRaw, err := stateConf.WaitForState() @@ -89,7 +89,7 @@ func WorkspaceAvailable(conn *workspaces.WorkSpaces, workspaceID string) (*works return nil, err } -func WorkspaceTerminated(conn *workspaces.WorkSpaces, workspaceID string) (*workspaces.Workspace, error) { +func WorkspaceTerminated(conn *workspaces.WorkSpaces, workspaceID string, timeout time.Duration) (*workspaces.Workspace, error) { stateConf := &resource.StateChangeConf{ Pending: []string{ workspaces.WorkspaceStatePending, @@ -111,7 +111,7 @@ func WorkspaceTerminated(conn *workspaces.WorkSpaces, workspaceID string) (*work }, Target: []string{}, Refresh: WorkspaceState(conn, workspaceID), - Timeout: WorkspaceTerminatedTimeout, + Timeout: timeout, } outputRaw, err := stateConf.WaitForState() @@ -123,7 +123,7 @@ func WorkspaceTerminated(conn *workspaces.WorkSpaces, workspaceID string) (*work return nil, err } -func WorkspaceUpdated(conn *workspaces.WorkSpaces, workspaceID string) (*workspaces.Workspace, error) { +func WorkspaceUpdated(conn *workspaces.WorkSpaces, workspaceID string, timeout time.Duration) (*workspaces.Workspace, error) { // OperationInProgressException: The properties of this WorkSpace are currently under modification. Please try again in a moment. // AWS Workspaces service doesn't change instance status to "Updating" during property modification. Respective AWS Support feature request has been created. Meanwhile, artificial delay is placed here as a workaround. stateConf := &resource.StateChangeConf{ @@ -136,7 +136,7 @@ func WorkspaceUpdated(conn *workspaces.WorkSpaces, workspaceID string) (*workspa }, Refresh: WorkspaceState(conn, workspaceID), Delay: WorkspaceUpdatingDelay, - Timeout: WorkspaceUpdatingTimeout, + Timeout: timeout, } outputRaw, err := stateConf.WaitForState() diff --git a/aws/resource_aws_workspaces_workspace.go b/aws/resource_aws_workspaces_workspace.go index 5bb710f7acb..aff74faabd3 100644 --- a/aws/resource_aws_workspaces_workspace.go +++ b/aws/resource_aws_workspaces_workspace.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/workspaces" @@ -132,6 +133,11 @@ func resourceAwsWorkspacesWorkspace() *schema.Resource { }, "tags": tagsSchema(), }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(waiter.WorkspaceAvailableTimeout), + Update: schema.DefaultTimeout(waiter.WorkspaceUpdatingTimeout), + Delete: schema.DefaultTimeout(waiter.WorkspaceTerminatedTimeout), + }, } } @@ -171,7 +177,7 @@ func resourceAwsWorkspacesWorkspaceCreate(d *schema.ResourceData, meta interface workspaceID := aws.StringValue(resp.PendingRequests[0].WorkspaceId) log.Printf("[DEBUG] Waiting for workspace %q to be available...", workspaceID) - _, err = waiter.WorkspaceAvailable(conn, workspaceID) + _, err = waiter.WorkspaceAvailable(conn, workspaceID, d.Timeout(schema.TimeoutCreate)) if err != nil { return fmt.Errorf("workspace %q is not available: %s", workspaceID, err) } @@ -272,7 +278,7 @@ func resourceAwsWorkspacesWorkspaceUpdate(d *schema.ResourceData, meta interface func resourceAwsWorkspacesWorkspaceDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).workspacesconn - err := workspaceDelete(d.Id(), conn) + err := workspaceDelete(conn, d.Id(), d.Timeout(schema.TimeoutDelete)) if err != nil { return err } @@ -280,7 +286,7 @@ func resourceAwsWorkspacesWorkspaceDelete(d *schema.ResourceData, meta interface return nil } -func workspaceDelete(id string, conn *workspaces.WorkSpaces) error { +func workspaceDelete(conn *workspaces.WorkSpaces, id string, timeout time.Duration) error { log.Printf("[DEBUG] Terminating workspace %q", id) _, err := conn.TerminateWorkspaces(&workspaces.TerminateWorkspacesInput{ TerminateWorkspaceRequests: []*workspaces.TerminateRequest{ @@ -294,7 +300,7 @@ func workspaceDelete(id string, conn *workspaces.WorkSpaces) error { } log.Printf("[DEBUG] Waiting for workspace %q to be terminated", id) - _, err = waiter.WorkspaceTerminated(conn, id) + _, err = waiter.WorkspaceTerminated(conn, id, timeout) if err != nil { return fmt.Errorf("workspace %q was not terminated: %s", id, err) } @@ -347,7 +353,7 @@ func workspacePropertyUpdate(p string, conn *workspaces.WorkSpaces, d *schema.Re } log.Printf("[DEBUG] Waiting for workspace %q %s property to be modified...", d.Id(), p) - _, err = waiter.WorkspaceUpdated(conn, d.Id()) + _, err = waiter.WorkspaceUpdated(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)) if err != nil { return fmt.Errorf("error modifying workspace %q property %q was not modified: %w", d.Id(), p, err) } diff --git a/aws/resource_aws_workspaces_workspace_test.go b/aws/resource_aws_workspaces_workspace_test.go index 3dadeace622..b07b338c9a9 100644 --- a/aws/resource_aws_workspaces_workspace_test.go +++ b/aws/resource_aws_workspaces_workspace_test.go @@ -13,6 +13,8 @@ import ( "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/terraform-providers/terraform-provider-aws/aws/internal/service/workspaces/waiter" ) func init() { @@ -33,7 +35,7 @@ func testSweepWorkspacesWorkspace(region string) error { input := &workspaces.DescribeWorkspacesInput{} err = conn.DescribeWorkspacesPages(input, func(resp *workspaces.DescribeWorkspacesOutput, _ bool) bool { for _, workspace := range resp.Workspaces { - err := workspaceDelete(aws.StringValue(workspace.WorkspaceId), conn) + err := workspaceDelete(conn, aws.StringValue(workspace.WorkspaceId), waiter.WorkspaceTerminatedTimeout) if err != nil { errors = multierror.Append(errors, err) } @@ -317,6 +319,33 @@ func TestAccAwsWorkspacesWorkspace_recreate(t *testing.T) { }) } +func TestAccAwsWorkspacesWorkspace_timeout(t *testing.T) { + var v workspaces.Workspace + rName := acctest.RandString(8) + + resourceName := "aws_workspaces_workspace.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccPreCheckWorkspacesDirectory(t) + testAccPreCheckAWSDirectoryServiceSimpleDirectory(t) + testAccPreCheckHasIAMRole(t, "workspaces_DefaultRole") + }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWorkspacesWorkspaceDestroy, + Steps: []resource.TestStep{ + { + Destroy: false, + Config: testAccWorkspacesWorkspaceConfig_timeout(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAwsWorkspacesWorkspaceExists(resourceName, &v), + ), + }, + }, + }) +} + func testAccCheckAwsWorkspacesWorkspaceDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).workspacesconn @@ -555,6 +584,25 @@ resource "aws_workspaces_workspace" "test" { ` } +func testAccWorkspacesWorkspaceConfig_timeout(rName string) string { + return testAccAwsWorkspacesWorkspaceConfig_Prerequisites(rName) + ` +resource "aws_workspaces_workspace" "test" { + bundle_id = data.aws_workspaces_bundle.test.id + directory_id = aws_workspaces_directory.test.id + + # NOTE: WorkSpaces API doesn't allow creating users in the directory. + # However, "Administrator"" user is always present in a bare directory. + user_name = "Administrator" + + timeouts { + create = "60m" + update = "30m" + delete = "30m" + } +} +` +} + func TestExpandWorkspaceProperties(t *testing.T) { cases := []struct { input []interface{} diff --git a/website/docs/r/workspaces_workspace.html.markdown b/website/docs/r/workspaces_workspace.html.markdown index 4f5211a1edf..c27790ff88a 100644 --- a/website/docs/r/workspaces_workspace.html.markdown +++ b/website/docs/r/workspaces_workspace.html.markdown @@ -64,6 +64,15 @@ The following arguments are supported: * `running_mode_auto_stop_timeout_in_minutes` – (Optional) The time after a user logs off when WorkSpaces are automatically stopped. Configured in 60-minute intervals. * `user_volume_size_gib` – (Optional) The size of the user storage. +### Timeouts + +`aws_workspaces_workspace` provides the following +[Timeouts](/docs/configuration/resources.html#operation-timeouts) configuration options: + +- `create` - (Default `30 minutes`) Used for WorkSpace creation. +- `update` - (Default `10 minutes`) Used for WorkSpace updating. +- `delete` - (Default `10 minutes`) Used for WorkSpace termination. + ## Attributes Reference In addition to all arguments above, the following attributes are exported: From 5f6cce0619a64e9490ca29eab93fc928f6ab7c6a Mon Sep 17 00:00:00 2001 From: Andrew Babichev Date: Mon, 9 Nov 2020 12:41:20 +0200 Subject: [PATCH 2/2] Sort imports --- aws/resource_aws_workspaces_workspace_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/aws/resource_aws_workspaces_workspace_test.go b/aws/resource_aws_workspaces_workspace_test.go index b07b338c9a9..eee59e1a254 100644 --- a/aws/resource_aws_workspaces_workspace_test.go +++ b/aws/resource_aws_workspaces_workspace_test.go @@ -13,7 +13,6 @@ import ( "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/terraform-providers/terraform-provider-aws/aws/internal/service/workspaces/waiter" )