Skip to content

Commit 1751135

Browse files
feat: fix: role_privilege_grant endpoint, error messages, map mutation, and wildcard value preservation (#59)
2 parents f5771e9 + 5e1f188 commit 1751135

2 files changed

Lines changed: 61 additions & 13 deletions

File tree

internal/client/client.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,10 @@ func (c *GalaxyClient) doRequestWithRetry(ctx context.Context, method, path stri
201201
}
202202

203203
if resp.StatusCode == http.StatusNotFound {
204+
bodyBytes, _ := io.ReadAll(resp.Body)
205+
if len(bodyBytes) > 0 {
206+
return &NotFoundError{Message: string(bodyBytes)}
207+
}
204208
return &NotFoundError{Message: fmt.Sprintf("resource not found: %s", path)}
205209
}
206210

@@ -516,7 +520,6 @@ func (c *GalaxyClient) ListDataProducts(ctx context.Context) ([]map[string]inter
516520

517521
// Role Privilege Grant methods
518522
func (c *GalaxyClient) CreateRolePrivilegeGrant(ctx context.Context, grant interface{}) (map[string]interface{}, error) {
519-
// Extract roleId from the grant request
520523
grantMap, ok := grant.(map[string]interface{})
521524
if !ok {
522525
return nil, fmt.Errorf("grant must be a map")
@@ -527,11 +530,16 @@ func (c *GalaxyClient) CreateRolePrivilegeGrant(ctx context.Context, grant inter
527530
return nil, fmt.Errorf("roleId is required")
528531
}
529532

530-
// Remove roleId from request body as it's in the URL
531-
delete(grantMap, "roleId")
533+
// Copy map excluding roleId (which goes in URL path, not request body)
534+
requestBody := make(map[string]interface{})
535+
for k, v := range grantMap {
536+
if k != "roleId" {
537+
requestBody[k] = v
538+
}
539+
}
532540

533541
var result map[string]interface{}
534-
err := c.doRequest(ctx, "POST", "/public/api/v1/role/"+roleId+"/privilege:grant", grantMap, &result)
542+
err := c.doRequest(ctx, "POST", "/public/api/v1/role/"+roleId+"/privilege:grant", requestBody, &result)
535543
return result, err
536544
}
537545

internal/provider/role_privilege_grant_resource.go

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -212,20 +212,52 @@ func (r *role_privilege_grantResource) Delete(ctx context.Context, req resource.
212212
return
213213
}
214214

215-
id := state.EntityId.ValueString()
216-
tflog.Debug(ctx, "Deleting role_privilege_grant", map[string]interface{}{"id": id})
217-
err := r.client.DeleteRolePrivilegeGrant(ctx, id)
215+
// Build the revoke request using the same approach as Update
216+
roleId := state.RoleId.ValueString()
217+
entityId := state.EntityId.ValueString()
218+
entityKind := state.EntityKind.ValueString()
219+
privilege := state.Privilege.ValueString()
220+
221+
tflog.Debug(ctx, "Deleting role_privilege_grant", map[string]interface{}{
222+
"roleId": roleId,
223+
"entityId": entityId,
224+
"privilege": privilege,
225+
})
226+
227+
// Create the revoke request
228+
revokeRequest := make(map[string]interface{})
229+
revokeRequest["entityId"] = entityId
230+
revokeRequest["entityKind"] = entityKind
231+
revokeRequest["privilege"] = privilege
232+
revokeRequest["revokeAction"] = "RemoveRoleGrant"
233+
234+
// Include optional scope fields if set
235+
if !state.ColumnName.IsNull() && state.ColumnName.ValueString() != "" {
236+
revokeRequest["columnName"] = state.ColumnName.ValueString()
237+
}
238+
if !state.SchemaName.IsNull() && state.SchemaName.ValueString() != "" {
239+
revokeRequest["schemaName"] = state.SchemaName.ValueString()
240+
}
241+
if !state.TableName.IsNull() && state.TableName.ValueString() != "" {
242+
revokeRequest["tableName"] = state.TableName.ValueString()
243+
}
244+
245+
err := r.client.RevokeRolePrivilege(ctx, roleId, revokeRequest)
218246
if err != nil {
219247
if !client.IsNotFound(err) {
220248
resp.Diagnostics.AddError(
221249
"Error deleting role_privilege_grant",
222-
"Could not delete role_privilege_grant "+id+": "+err.Error(),
250+
"Could not delete role_privilege_grant: "+err.Error(),
223251
)
224252
return
225253
}
226254
}
227255

228-
tflog.Debug(ctx, "Deleted role_privilege_grant", map[string]interface{}{"id": id})
256+
tflog.Debug(ctx, "Deleted role_privilege_grant", map[string]interface{}{
257+
"roleId": roleId,
258+
"entityId": entityId,
259+
"privilege": privilege,
260+
})
229261
}
230262

231263
// Helper methods
@@ -300,31 +332,39 @@ func (r *role_privilege_grantResource) updateModelFromResponse(ctx context.Conte
300332
model.GrantOption = types.BoolValue(grantOption)
301333
}
302334

335+
// For optional scope fields (columnName, schemaName, tableName), preserve plan values
336+
// when the API doesn't return them. This handles the case where users specify wildcard
337+
// values like "*" that the API accepts but doesn't echo back in the response.
338+
// If the plan value is null/unknown, set to null (must be known after apply).
303339
if columnName, ok := response["columnName"].(string); ok {
304340
model.ColumnName = types.StringValue(columnName)
305-
} else {
341+
} else if model.ColumnName.IsNull() || model.ColumnName.IsUnknown() {
306342
model.ColumnName = types.StringNull()
307343
}
344+
// Otherwise keep existing model value (user-specified value like "*")
308345

309346
if schemaName, ok := response["schemaName"].(string); ok {
310347
model.SchemaName = types.StringValue(schemaName)
311-
} else {
348+
} else if model.SchemaName.IsNull() || model.SchemaName.IsUnknown() {
312349
model.SchemaName = types.StringNull()
313350
}
351+
// Otherwise keep existing model value (user-specified value like "*")
314352

315353
if tableName, ok := response["tableName"].(string); ok {
316354
model.TableName = types.StringValue(tableName)
317-
} else {
355+
} else if model.TableName.IsNull() || model.TableName.IsUnknown() {
318356
model.TableName = types.StringNull()
319357
}
358+
// Otherwise keep existing model value (user-specified value like "*")
320359

321360
// Note: Pagination fields are not part of the model as they are handled at the framework level
322361

323362
if listAllPrivileges, ok := response["listAllPrivileges"].(bool); ok {
324363
model.ListAllPrivileges = types.BoolValue(listAllPrivileges)
325-
} else {
364+
} else if model.ListAllPrivileges.IsNull() || model.ListAllPrivileges.IsUnknown() {
326365
model.ListAllPrivileges = types.BoolNull()
327366
}
367+
// Otherwise keep existing model value
328368

329369
// Note: Role privilege grants are individual operations, not list operations
330370
}

0 commit comments

Comments
 (0)