Skip to content

Commit adc0503

Browse files
committed
fix: handle user deletion config drift
1 parent d085864 commit adc0503

File tree

3 files changed

+44
-1
lines changed

3 files changed

+44
-1
lines changed

internal/provider/user_resource.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ func (r *UserResource) Read(ctx context.Context, req resource.ReadRequest, resp
248248

249249
client := r.data.Client
250250

251+
// Lookup by ID to handle imports
251252
user, err := client.User(ctx, data.ID.ValueString())
252253
if err != nil {
253254
if isNotFound(err) {
@@ -274,6 +275,23 @@ func (r *UserResource) Read(ctx context.Context, req resource.ReadRequest, resp
274275
data.LoginType = types.StringValue(string(user.LoginType))
275276
data.Suspended = types.BoolValue(user.Status == codersdk.UserStatusSuspended)
276277

278+
// Also query by username to check for deletion or username reassignment
279+
userByName, err := client.User(ctx, data.Username.ValueString())
280+
if err != nil {
281+
if isNotFound(err) {
282+
resp.Diagnostics.AddWarning("Client Warning", fmt.Sprintf("User with ID %q not found. Marking as deleted.", data.ID.ValueString()))
283+
resp.State.RemoveResource(ctx)
284+
return
285+
}
286+
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to get current user, got error: %s", err))
287+
return
288+
}
289+
if userByName.ID != data.ID.ValueUUID() {
290+
resp.Diagnostics.AddWarning("Client Error", fmt.Sprintf("The username %q has been reassigned to a new user. Marking as deleted.", user.Username))
291+
resp.State.RemoveResource(ctx)
292+
return
293+
}
294+
277295
// Save updated data into Terraform state
278296
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
279297
}

internal/provider/user_resource_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/coder/coder/v2/coderd/util/ptr"
1111
"github.com/coder/terraform-provider-coderd/integration"
1212
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
13+
"github.com/hashicorp/terraform-plugin-testing/terraform"
1314
"github.com/stretchr/testify/require"
1415
)
1516

@@ -101,6 +102,19 @@ func TestAccUserResource(t *testing.T) {
101102
resource.TestCheckResourceAttr("coderd_user.test", "login_type", "github"),
102103
),
103104
},
105+
// Verify config drift via deletion is handled
106+
{
107+
Config: cfg4.String(t),
108+
Check: func(*terraform.State) error {
109+
user, err := client.User(ctx, "exampleNew")
110+
if err != nil {
111+
return err
112+
}
113+
return client.DeleteUser(ctx, user.ID)
114+
},
115+
// The Plan should be to create the entire resource
116+
ExpectNonEmptyPlan: true,
117+
},
104118
},
105119
})
106120
}

internal/provider/util.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net/http"
99
"os"
1010
"path/filepath"
11+
"strings"
1112

1213
"github.com/coder/coder/v2/codersdk"
1314
"github.com/google/uuid"
@@ -110,5 +111,15 @@ func memberDiff(currentMembers []uuid.UUID, plannedMembers []UUID) (add, remove
110111

111112
func isNotFound(err error) bool {
112113
var sdkErr *codersdk.Error
113-
return errors.As(err, &sdkErr) && sdkErr.StatusCode() == http.StatusNotFound
114+
if !errors.As(err, &sdkErr) {
115+
return false
116+
}
117+
if sdkErr.StatusCode() == http.StatusNotFound {
118+
return true
119+
}
120+
// `httpmw/ExtractUserContext` returns a 400 w/ this message if the user is not found
121+
if sdkErr.StatusCode() == http.StatusBadRequest && strings.Contains(sdkErr.Message, "must be an existing uuid or username") {
122+
return true
123+
}
124+
return false
114125
}

0 commit comments

Comments
 (0)
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