From 4813553a1d0a9a3bd774bc25881028d060f319a8 Mon Sep 17 00:00:00 2001 From: Ethan Dickson Date: Tue, 16 Jul 2024 06:37:30 +0000 Subject: [PATCH 1/2] feat: allow email updates in user resources --- internal/provider/user_resource.go | 3 +++ internal/provider/user_resource_test.go | 35 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/internal/provider/user_resource.go b/internal/provider/user_resource.go index 9bc8018..2dd79d1 100644 --- a/internal/provider/user_resource.go +++ b/internal/provider/user_resource.go @@ -81,6 +81,9 @@ func (r *UserResource) Schema(ctx context.Context, req resource.SchemaRequest, r "email": schema.StringAttribute{ MarkdownDescription: "Email address of the user.", Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, }, "roles": schema.SetAttribute{ MarkdownDescription: "Roles assigned to the user. Valid roles are 'owner', 'template-admin', 'user-admin', and 'auditor'.", diff --git a/internal/provider/user_resource_test.go b/internal/provider/user_resource_test.go index f955310..40a91ae 100644 --- a/internal/provider/user_resource_test.go +++ b/internal/provider/user_resource_test.go @@ -10,6 +10,7 @@ import ( "github.com/coder/terraform-provider-coderd/integration" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/stretchr/testify/require" ) @@ -35,6 +36,10 @@ func TestAccUserResource(t *testing.T) { cfg2.Username = PtrTo("exampleNew") cfg2.Name = PtrTo("Example User New") + cfg3 := cfg1 + cfg3.Email = PtrTo("example2@coder.com") + + var userId string resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, @@ -68,6 +73,15 @@ func TestAccUserResource(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("coderd_user.test", "username", "exampleNew"), resource.TestCheckResourceAttr("coderd_user.test", "name", "Example User New"), + testAccIdChanged("coderd_user.test", &userId), + ), + }, + // Replace testing + { + Config: cfg3.String(t), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("coderd_user.test", "email", "example2@coder.com"), + testAccIdChanged("coderd_user.test", &userId), ), }, // Delete testing automatically occurs in TestCase @@ -151,3 +165,24 @@ resource "coderd_user" "test" { return buf.String() } + +// Check if the id has changed since the last time this check function was run. +func testAccIdChanged(resourceName string, id *string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Resource %s not found", resourceName) + } + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + if *id == "" { + *id = rs.Primary.ID + return nil + } + if rs.Primary.ID == *id { + return fmt.Errorf("ID did not change from %s", rs.Primary.ID) + } + return nil + } +} From 6c22e1b9c3e08922bb848a7eab6a35e06ef29d87 Mon Sep 17 00:00:00 2001 From: Ethan Dickson Date: Tue, 16 Jul 2024 10:53:46 +0000 Subject: [PATCH 2/2] cascade delete --- internal/provider/user_resource.go | 47 +++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/internal/provider/user_resource.go b/internal/provider/user_resource.go index 2dd79d1..907e203 100644 --- a/internal/provider/user_resource.go +++ b/internal/provider/user_resource.go @@ -41,13 +41,14 @@ type UserResource struct { type UserResourceModel struct { ID types.String `tfsdk:"id"` - Username types.String `tfsdk:"username"` - Name types.String `tfsdk:"name"` - Email types.String `tfsdk:"email"` - Roles types.Set `tfsdk:"roles"` // owner, template-admin, user-admin, auditor (member is implicit) - LoginType types.String `tfsdk:"login_type"` // none, password, github, oidc - Password types.String `tfsdk:"password"` // only when login_type is password - Suspended types.Bool `tfsdk:"suspended"` + Username types.String `tfsdk:"username"` + Name types.String `tfsdk:"name"` + Email types.String `tfsdk:"email"` + Roles types.Set `tfsdk:"roles"` // owner, template-admin, user-admin, auditor (member is implicit) + LoginType types.String `tfsdk:"login_type"` // none, password, github, oidc + Password types.String `tfsdk:"password"` // only when login_type is password + Suspended types.Bool `tfsdk:"suspended"` + CascadeDelete types.Bool `tfsdk:"cascade_delete"` } func (r *UserResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { @@ -79,7 +80,7 @@ func (r *UserResource) Schema(ctx context.Context, req resource.SchemaRequest, r // Defaulted in Create }, "email": schema.StringAttribute{ - MarkdownDescription: "Email address of the user.", + MarkdownDescription: "Email address of the user. Modifying this field will trigger a resource replacement.", Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), @@ -121,6 +122,13 @@ func (r *UserResource) Schema(ctx context.Context, req resource.SchemaRequest, r Optional: true, Default: booldefault.StaticBool(false), }, + "cascade_delete": schema.BoolAttribute{ + Computed: true, + MarkdownDescription: "Whether to delete owned workspaces when this resource is deleted or replaced.", + Required: false, + Optional: true, + Default: booldefault.StaticBool(false), + }, }, } } @@ -366,6 +374,29 @@ func (r *UserResource) Delete(ctx context.Context, req resource.DeleteRequest, r resp.Diagnostics.AddError("Data Error", fmt.Sprintf("Unable to parse user ID, got error: %s", err)) return } + + if data.CascadeDelete.ValueBool() { + tflog.Trace(ctx, "deleting user workspaces") + workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{ + Owner: data.Username.ValueString(), + }) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to get user workspaces, got error: %s", err)) + return + } + for _, workspace := range workspaces.Workspaces { + _, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ + Transition: codersdk.WorkspaceTransitionDelete, + }) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete user workspace, got error: %s", err)) + return + } + } + //TODO: Wait for builds to finish + tflog.Trace(ctx, "successfully deleted user workspaces") + } + tflog.Trace(ctx, "deleting user") err = client.DeleteUser(ctx, id) if err != nil { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy