fix(mongodb): User role should be updatable (#731)

Signed-off-by: Alexander Dahmen <alexander.dahmen@inovex.de>
This commit is contained in:
Alexander Dahmen 2025-03-26 14:19:28 +01:00 committed by GitHub
parent 91903f5a60
commit a2c25bede2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 168 additions and 3 deletions

View file

@ -287,9 +287,72 @@ func (r *userResource) Read(ctx context.Context, req resource.ReadRequest, resp
}
// Update updates the resource and sets the updated Terraform state on success.
func (r *userResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform
// Update shouldn't be called
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating user", "User can't be updated")
func (r *userResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform
// Retrieve values from plan
var model Model
diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
projectId := model.ProjectId.ValueString()
instanceId := model.InstanceId.ValueString()
userId := model.UserId.ValueString()
ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "instance_id", instanceId)
ctx = tflog.SetField(ctx, "user_id", userId)
// Retrieve values from state
var stateModel Model
diags = req.State.Get(ctx, &stateModel)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var roles []string
if !(model.Roles.IsNull() || model.Roles.IsUnknown()) {
diags = model.Roles.ElementsAs(ctx, &roles, false)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Generate API request body from model
payload, err := toUpdatePayload(&model, roles)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating user", fmt.Sprintf("Updating API payload: %v", err))
return
}
// Update existing instance
err = r.client.UpdateUser(ctx, projectId, instanceId, userId).UpdateUserPayload(*payload).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating user", err.Error())
return
}
userResp, err := r.client.GetUser(ctx, projectId, instanceId, userId).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating user", fmt.Sprintf("Calling API: %v", err))
return
}
// Map response body to schema
err = mapFields(userResp, &stateModel)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating user", fmt.Sprintf("Processing API payload: %v", err))
return
}
// Set state to fully populated data
diags = resp.State.Set(ctx, stateModel)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
tflog.Info(ctx, "MongoDB Flex user updated")
}
// Delete deletes the resource and removes the Terraform state on success.
@ -450,3 +513,17 @@ func toCreatePayload(model *Model, roles []string) (*mongodbflex.CreateUserPaylo
Database: conversion.StringValueToPointer(model.Database),
}, nil
}
func toUpdatePayload(model *Model, roles []string) (*mongodbflex.UpdateUserPayload, error) {
if model == nil {
return nil, fmt.Errorf("nil model")
}
if roles == nil {
return nil, fmt.Errorf("nil roles")
}
return &mongodbflex.UpdateUserPayload{
Roles: &roles,
Database: conversion.StringValueToPointer(model.Database),
}, nil
}

View file

@ -377,3 +377,91 @@ func TestToCreatePayload(t *testing.T) {
})
}
}
func TestToUpdatePayload(t *testing.T) {
tests := []struct {
description string
input *Model
inputRoles []string
expected *mongodbflex.UpdateUserPayload
isValid bool
}{
{
"default_values",
&Model{},
[]string{},
&mongodbflex.UpdateUserPayload{
Roles: &[]string{},
Database: nil,
},
true,
},
{
"simple values",
&Model{
Username: types.StringValue("username"),
Database: types.StringValue("database"),
},
[]string{
"role_1",
"role_2",
},
&mongodbflex.UpdateUserPayload{
Roles: &[]string{
"role_1",
"role_2",
},
Database: utils.Ptr("database"),
},
true,
},
{
"null_fields",
&Model{
Username: types.StringNull(),
Database: types.StringNull(),
},
[]string{
"",
},
&mongodbflex.UpdateUserPayload{
Roles: &[]string{
"",
},
Database: nil,
},
true,
},
{
"nil_model",
nil,
[]string{},
nil,
false,
},
{
"nil_roles",
&Model{},
nil,
nil,
false,
},
}
for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) {
output, err := toUpdatePayload(tt.input, tt.inputRoles)
if !tt.isValid && err == nil {
t.Fatalf("Should have failed")
}
if tt.isValid && err != nil {
t.Fatalf("Should not have failed: %v", err)
}
if tt.isValid {
diff := cmp.Diff(output, tt.expected)
if diff != "" {
t.Fatalf("Data does not match: %s", diff)
}
}
})
}
}