Skip to content

Commit

Permalink
Add azuread_directory_role_eligibility_schedule_request resource
Browse files Browse the repository at this point in the history
  • Loading branch information
JonasBak committed May 3, 2023
1 parent 2c1c00e commit a48155a
Show file tree
Hide file tree
Showing 7 changed files with 327 additions and 15 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,5 @@ require (
)

go 1.19

replace github.com/manicminer/hamilton => ../hamilton
25 changes: 15 additions & 10 deletions internal/services/directoryroles/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import (
)

type Client struct {
DirectoryObjectsClient *msgraph.DirectoryObjectsClient
DirectoryRolesClient *msgraph.DirectoryRolesClient
DirectoryRoleTemplatesClient *msgraph.DirectoryRoleTemplatesClient
RoleAssignmentsClient *msgraph.RoleAssignmentsClient
RoleDefinitionsClient *msgraph.RoleDefinitionsClient
DirectoryObjectsClient *msgraph.DirectoryObjectsClient
DirectoryRolesClient *msgraph.DirectoryRolesClient
DirectoryRoleTemplatesClient *msgraph.DirectoryRoleTemplatesClient
RoleAssignmentsClient *msgraph.RoleAssignmentsClient
RoleDefinitionsClient *msgraph.RoleDefinitionsClient
RoleEligibilityScheduleRequestClient *msgraph.RoleEligibilityScheduleRequestClient
}

func NewClient(o *common.ClientOptions) *Client {
Expand All @@ -29,11 +30,15 @@ func NewClient(o *common.ClientOptions) *Client {
roleDefinitionsClient := msgraph.NewRoleDefinitionsClient()
o.ConfigureClient(&roleDefinitionsClient.BaseClient)

roleEligibilityScheduleRequestClient := msgraph.NewRoleEligibilityScheduleRequestClient(o.TenantID)
o.ConfigureClient(&roleEligibilityScheduleRequestClient.BaseClient)

return &Client{
DirectoryObjectsClient: directoryObjectsClient,
DirectoryRolesClient: directoryRolesClient,
DirectoryRoleTemplatesClient: directoryRoleTemplatesClient,
RoleAssignmentsClient: roleAssignmentsClient,
RoleDefinitionsClient: roleDefinitionsClient,
DirectoryObjectsClient: directoryObjectsClient,
DirectoryRolesClient: directoryRolesClient,
DirectoryRoleTemplatesClient: directoryRoleTemplatesClient,
RoleAssignmentsClient: roleAssignmentsClient,
RoleDefinitionsClient: roleDefinitionsClient,
RoleEligibilityScheduleRequestClient: roleEligibilityScheduleRequestClient,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package directoryroles

import (
"context"
"errors"
"fmt"
"log"
"net/http"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-azuread/internal/clients"
"github.com/hashicorp/terraform-provider-azuread/internal/tf"
"github.com/hashicorp/terraform-provider-azuread/internal/validate"
"github.com/manicminer/hamilton/msgraph"
"github.com/hashicorp/go-azure-sdk/sdk/odata"
)

func directoryRoleEligibilityScheduleRequestResource() *schema.Resource {
return &schema.Resource{
CreateContext: directoryRoleEligibilityScheduleRequestResourceCreate,
ReadContext: directoryRoleEligibilityScheduleRequestResourceRead,
DeleteContext: directoryRoleEligibilityScheduleRequestResourceDelete,

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(5 * time.Minute),
Read: schema.DefaultTimeout(5 * time.Minute),
Update: schema.DefaultTimeout(5 * time.Minute),
Delete: schema.DefaultTimeout(5 * time.Minute),
},

Importer: tf.ValidateResourceIDPriorToImport(func(id string) error {
if id == "" {
return errors.New("id was empty")
}
return nil
}),

Schema: map[string]*schema.Schema{
"role_definition_id": {
Description: "The object ID of the directory role for this assignment",
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateDiagFunc: validate.UUID,
},

"principal_id": {
Description: "The object ID of the member principal",
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateDiagFunc: validate.UUID,
},

"directory_scope_id": {
Description: "Identifier of the directory object representing the scope of the assignment",
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateDiagFunc: validate.NoEmptyStrings,
},

"justification": {
Description: "Justification for why the role is assigned",
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateDiagFunc: validate.NoEmptyStrings,
},
},
}
}

func directoryRoleEligibilityScheduleRequestResourceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*clients.Client).DirectoryRoles.RoleEligibilityScheduleRequestClient

roleDefinitionId := d.Get("role_definition_id").(string)
principalId := d.Get("principal_id").(string)
justification := d.Get("justification").(string)
directoryScopeId := d.Get("directory_scope_id").(string)

var expiration interface{} = struct {
Type string `json:"type"`
}{
Type: "NoExpiration",
}
var scheduleInfo interface{} = struct {
StartDateTime string `json:"startDateTime"`
Expiration interface{} `json:"expiration"`
}{
StartDateTime: time.Now().UTC().Format(time.RFC3339),
Expiration: expiration,
}

properties := msgraph.UnifiedRoleEligibilityScheduleRequest{
RoleDefinitionId: &roleDefinitionId,
PrincipalId: &principalId,
Justification: &justification,
DirectoryScopeId: &directoryScopeId,
ScheduleInfo: &scheduleInfo,
}

assignment, status, err := client.Create(ctx, properties)
if err != nil {
return tf.ErrorDiagF(err, "Eligibility schedule request for role %q to principal %q, received %d with error: %+v", roleDefinitionId, principalId, status, err)
}
if assignment == nil || assignment.ID() == nil {
return tf.ErrorDiagF(errors.New("returned role assignment ID was nil"), "API Error")
}

d.SetId(*assignment.ID())

deadline, ok := ctx.Deadline()
if !ok {
return tf.ErrorDiagF(errors.New("context has no deadline"), "Waiting for directory role %q eligibility schedule request to principal %q to take effect", roleDefinitionId, principalId)
}
timeout := time.Until(deadline)
_, err = (&resource.StateChangeConf{
Pending: []string{"Waiting"},
Target: []string{"Done"},
Timeout: timeout,
MinTimeout: 1 * time.Second,
ContinuousTargetOccurence: 3,
Refresh: func() (interface{}, string, error) {
_, status, err := client.Get(ctx, *assignment.ID(), odata.Query{})
if err != nil {
if status == http.StatusNotFound {
return "stub", "Waiting", nil
}
return nil, "Error", fmt.Errorf("retrieving role assignment")
}
return "stub", "Done", nil
},
}).WaitForStateContext(ctx)
if err != nil {
return tf.ErrorDiagF(err, "Waiting for role eligibility schedule request for %q to reflect in directory role %q", principalId, roleDefinitionId)
}

return directoryRoleEligibilityScheduleRequestResourceRead(ctx, d, meta)
}

func directoryRoleEligibilityScheduleRequestResourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*clients.Client).DirectoryRoles.RoleEligibilityScheduleRequestClient

id := d.Id()
assignment, status, err := client.Get(ctx, id, odata.Query{})
if err != nil {
if status == http.StatusNotFound {
log.Printf("[DEBUG] Assignment with ID %q was not found - removing from state", id)
d.SetId("")
return nil
}
return tf.ErrorDiagF(err, "Retrieving role assignment %q", id)
}

tf.Set(d, "role_definition_id", assignment.RoleDefinitionId)
tf.Set(d, "principal_id", assignment.PrincipalId)
tf.Set(d, "justification", assignment.Justification)
tf.Set(d, "directory_scope_id", assignment.DirectoryScopeId)

return nil
}

func directoryRoleEligibilityScheduleRequestResourceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*clients.Client).DirectoryRoles.RoleEligibilityScheduleRequestClient

if _, err := client.Delete(ctx, d.Id()); err != nil {
return tf.ErrorDiagF(err, "Deleting role assignment %q: %+v", d.Id(), err)
}
return nil
}
9 changes: 5 additions & 4 deletions internal/services/directoryroles/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ func (r Registration) SupportedDataSources() map[string]*schema.Resource {
// SupportedResources returns the supported Resources supported by this Service
func (r Registration) SupportedResources() map[string]*schema.Resource {
return map[string]*schema.Resource{
"azuread_custom_directory_role": customDirectoryRoleResource(),
"azuread_directory_role": directoryRoleResource(),
"azuread_directory_role_assignment": directoryRoleAssignmentResource(),
"azuread_directory_role_member": directoryRoleMemberResource(),
"azuread_custom_directory_role": customDirectoryRoleResource(),
"azuread_directory_role": directoryRoleResource(),
"azuread_directory_role_assignment": directoryRoleAssignmentResource(),
"azuread_directory_role_member": directoryRoleMemberResource(),
"azuread_directory_role_eligibility_schedule_request": directoryRoleEligibilityScheduleRequestResource(),
}
}
11 changes: 11 additions & 0 deletions vendor/github.com/manicminer/hamilton/msgraph/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ github.com/hashicorp/terraform-svchost
# github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87
## explicit; go 1.15
github.com/hashicorp/yamux
# github.com/manicminer/hamilton v0.61.0
# github.com/manicminer/hamilton v0.61.0 => ../hamilton
## explicit; go 1.16
github.com/manicminer/hamilton/errors
github.com/manicminer/hamilton/internal/utils
Expand Down Expand Up @@ -371,3 +371,4 @@ google.golang.org/protobuf/types/known/timestamppb
## explicit; go 1.15
software.sslmate.com/src/go-pkcs12
software.sslmate.com/src/go-pkcs12/internal/rc2
# github.com/manicminer/hamilton => ../hamilton

0 comments on commit a48155a

Please sign in to comment.