Skip to content

Commit

Permalink
[resource_datadog_role] ACCESS-2867 - Support `default_permissions_op…
Browse files Browse the repository at this point in the history
…t_out` attribute in Terraform (#2710)

* schema change

* support role updates

---------

Co-authored-by: skarimo <[email protected]>
  • Loading branch information
wangwillson1 and skarimo authored Jan 7, 2025
1 parent f421aba commit 3cfd682
Show file tree
Hide file tree
Showing 8 changed files with 985 additions and 188 deletions.
83 changes: 59 additions & 24 deletions datadog/resource_datadog_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

// validPermissions is a map of all unrestricted permission IDs to their name
var validPermissions map[string]string
type PermAttributes struct {
Name string
IsDefaultPermission bool
}

// allPermissions is a map of all permission IDs to its attributes (name, restricted)
var allPermissions map[string]PermAttributes

func resourceDatadogRole() *schema.Resource {
return &schema.Resource{
Expand All @@ -36,6 +41,11 @@ func resourceDatadogRole() *schema.Resource {
Required: true,
Description: "Name of the role.",
},
"default_permissions_opt_out": {
Type: schema.TypeBool,
Optional: true,
Description: "If set to `true`, the role does not have default (restricted) permissions unless they are explicitly set. The `include_restricted` attribute for the `datadog_permissions` data source must be set to `true` to manage default permissions in Terraform.",
},
"permission": {
Type: schema.TypeSet,
Optional: true,
Expand Down Expand Up @@ -80,23 +90,21 @@ func GetRolePermissionSchema() *schema.Resource {
}
}

func getValidPermissions(ctx context.Context, apiInstances *utils.ApiInstances) (map[string]string, error) {
// Get a list of all permissions, to ignore restricted perms
if validPermissions == nil {
func getValidPermissions(ctx context.Context, apiInstances *utils.ApiInstances) (map[string]PermAttributes, error) {
if allPermissions == nil {
res, httpResponse, err := apiInstances.GetRolesApiV2().ListPermissions(ctx)
if err != nil {
return nil, utils.TranslateClientError(err, httpResponse, "error listing permissions")
}
permsList := res.GetData()
permsNameToID := make(map[string]string, len(permsList))

newPerms := make(map[string]PermAttributes, len(permsList))
for _, perm := range permsList {
if !perm.Attributes.GetRestricted() {
permsNameToID[perm.GetId()] = perm.Attributes.GetName()
}
newPerms[perm.GetId()] = PermAttributes{perm.Attributes.GetName(), perm.Attributes.GetRestricted()}
}
validPermissions = permsNameToID
allPermissions = newPerms
}
return validPermissions, nil
return allPermissions, nil
}

func resourceDatadogRoleCustomizeDiff(ctx context.Context, diff *schema.ResourceDiff, meta interface{}) error {
Expand All @@ -110,11 +118,13 @@ func resourceDatadogRoleCustomizeDiff(ctx context.Context, diff *schema.Resource
return nil
}

defaultPermissionsOptOut, _ := diff.GetOk("default_permissions_opt_out")

apiInstances := meta.(*ProviderConfiguration).DatadogApiInstances
auth := meta.(*ProviderConfiguration).Auth

// Get a list of all valid permissions
validPerms, err := getValidPermissions(auth, apiInstances)
allPerms, err := getValidPermissions(auth, apiInstances)
if err != nil {
return err
}
Expand All @@ -123,9 +133,19 @@ func resourceDatadogRoleCustomizeDiff(ctx context.Context, diff *schema.Resource
for _, permI := range perms.List() {
perm := permI.(map[string]interface{})
permID := perm["id"].(string)
if _, ok := validPerms[permID]; !ok {

permAttributes, permissionExists := allPerms[permID]

if !permissionExists {
return fmt.Errorf(
"permission with ID %s is restricted and cannot be managed by terraform or does not exist, remove it from your configuration",
"permission with ID %s does not exist, remove it from your configuration",
permID,
)
}

if permAttributes.IsDefaultPermission && !defaultPermissionsOptOut.(bool) {
return fmt.Errorf(
"permission with ID %s is a restricted (default) permission and cannot be managed by terraform, remove it from your configuration",
permID,
)
}
Expand Down Expand Up @@ -202,21 +222,23 @@ func updateRoleState(ctx context.Context, d *schema.ResourceData, roleAttrsI int

func updateRolePermissionsState(ctx context.Context, d *schema.ResourceData, rolePermsI interface{}, apiInstances *utils.ApiInstances) diag.Diagnostics {

// Get a list of all valid permissions, to ignore restricted perms
permsIDToName, err := getValidPermissions(ctx, apiInstances)
// Get a list of all valid permissions
allPermissions, err := getValidPermissions(ctx, apiInstances)
if err != nil {
return diag.FromErr(err)
}

isOptedOutOfDefaultPermissions := d.Get("default_permissions_opt_out").(bool)

var perms []map[string]string
switch rolePerms := rolePermsI.(type) {
case []datadogV2.RelationshipToPermissionData:
for _, perm := range rolePerms {
perms = appendPerm(perms, perm.GetId(), permsIDToName)
perms = appendPerm(perms, perm.GetId(), allPermissions, isOptedOutOfDefaultPermissions)
}
case []datadogV2.Permission:
for _, perm := range rolePerms {
perms = appendPerm(perms, perm.GetId(), permsIDToName)
perms = appendPerm(perms, perm.GetId(), allPermissions, isOptedOutOfDefaultPermissions)
}
default:
return diag.Errorf("unexpected type %s for permissions list", reflect.TypeOf(rolePermsI).String())
Expand All @@ -228,14 +250,16 @@ func updateRolePermissionsState(ctx context.Context, d *schema.ResourceData, rol
return nil
}

func appendPerm(perms []map[string]string, permID string, permsIDToName map[string]string) []map[string]string {
// If perm ID is not restricted, add it to the state
if permName, ok := permsIDToName[permID]; ok {
func appendPerm(perms []map[string]string, permID string, permIDToAttributes map[string]PermAttributes, isOptedOutOfDefaultPermissions bool) []map[string]string {
if permAttributes, ok := permIDToAttributes[permID]; ok {
permR := map[string]string{
"id": permID,
"name": permName,
"name": permAttributes.Name,
}
// we include the permission if it's not a default (restricted) permission or if the config has opted out of automatically including default permissions
if isOptedOutOfDefaultPermissions || !permAttributes.IsDefaultPermission {
perms = append(perms, permR)
}
perms = append(perms, permR)
}
return perms
}
Expand Down Expand Up @@ -264,7 +288,7 @@ func resourceDatadogRoleUpdate(ctx context.Context, d *schema.ResourceData, meta
apiInstances := meta.(*ProviderConfiguration).DatadogApiInstances
auth := meta.(*ProviderConfiguration).Auth

if d.HasChange("name") || d.HasChange("permission") {
if d.HasChange("name") || d.HasChange("permission") || d.HasChange("default_permissions_opt_out") {
roleReq := buildRoleUpdateRequest(d)
resp, httpResponse, err := apiInstances.GetRolesApiV2().UpdateRole(auth, d.Id(), *roleReq)
if err != nil {
Expand Down Expand Up @@ -302,6 +326,11 @@ func buildRoleCreateRequest(d *schema.ResourceData) *datadogV2.RoleCreateRequest

// Set attributes
roleCreateAttrs.SetName(d.Get("name").(string))
if d.Get("default_permissions_opt_out").(bool) {
roleCreateAttrs.AdditionalProperties = map[string]any{
"default_permissions_opt_out": true,
}
}
roleCreateData.SetAttributes(*roleCreateAttrs)

// Set permission relationships
Expand Down Expand Up @@ -335,6 +364,12 @@ func buildRoleUpdateRequest(d *schema.ResourceData) *datadogV2.RoleUpdateRequest
}

roleUpdateData.SetId(d.Id())

if d.Get("default_permissions_opt_out").(bool) {
roleUpdateAttributes.AdditionalProperties = map[string]any{
"default_permissions_opt_out": true,
}
}
roleUpdateData.SetAttributes(*roleUpdateAttributes)

// Set permission relationships
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2024-05-10T14:49:08.268476-04:00
2024-12-10T17:15:59.253508-05:00
892 changes: 768 additions & 124 deletions datadog/tests/cassettes/TestAccDatadogRole_CreateUpdate.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1 +1 @@
2022-07-26T10:43:12.182854-04:00
2025-01-02T11:18:48.106262-05:00
Loading

0 comments on commit 3cfd682

Please sign in to comment.