Skip to content

Commit

Permalink
SDK Migration: migrate approleassignments to go-azure-sdk
Browse files Browse the repository at this point in the history
  • Loading branch information
manicminer committed Sep 23, 2024
1 parent c7fa966 commit 6322617
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@ package approleassignments
import (
"context"
"errors"
"fmt"
"github.com/hashicorp/go-azure-sdk/sdk/odata"
"log"
"net/http"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-sdk/sdk/odata"
"github.com/hashicorp/go-azure-helpers/lang/response"
"github.com/hashicorp/go-azure-sdk/microsoft-graph/common-types/stable"
"github.com/hashicorp/go-azure-sdk/microsoft-graph/serviceprincipals/stable/approleassignedto"
"github.com/hashicorp/go-azure-sdk/microsoft-graph/serviceprincipals/stable/serviceprincipal"
"github.com/hashicorp/go-azure-sdk/sdk/nullable"
"github.com/hashicorp/terraform-provider-azuread/internal/clients"
"github.com/hashicorp/terraform-provider-azuread/internal/helpers/tf"
"github.com/hashicorp/terraform-provider-azuread/internal/helpers/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azuread/internal/helpers/tf/validation"
"github.com/hashicorp/terraform-provider-azuread/internal/services/approleassignments/parse"
"github.com/hashicorp/terraform-provider-azuread/internal/tf"
"github.com/hashicorp/terraform-provider-azuread/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azuread/internal/tf/validation"
"github.com/manicminer/hamilton/msgraph"
)

func appRoleAssignmentResource() *pluginsdk.Resource {
Expand Down Expand Up @@ -86,37 +89,55 @@ func appRoleAssignmentResource() *pluginsdk.Resource {

func appRoleAssignmentResourceCreate(ctx context.Context, d *pluginsdk.ResourceData, meta interface{}) pluginsdk.Diagnostics {
client := meta.(*clients.Client).AppRoleAssignments.AppRoleAssignedToClient
servicePrincipalsClient := meta.(*clients.Client).AppRoleAssignments.ServicePrincipalsClient
servicePrincipalClient := meta.(*clients.Client).AppRoleAssignments.ServicePrincipalClient

appRoleId := d.Get("app_role_id").(string)
principalId := d.Get("principal_object_id").(string)
resourceId := d.Get("resource_object_id").(string)
if _, status, err := servicePrincipalsClient.Get(ctx, resourceId, odata.Query{}); err != nil {
if status == http.StatusNotFound {

if resp, err := servicePrincipalClient.GetServicePrincipal(ctx, stable.NewServicePrincipalID(resourceId), serviceprincipal.DefaultGetServicePrincipalOperationOptions()); err != nil {
if response.WasNotFound(resp.HttpResponse) {
return tf.ErrorDiagPathF(err, "principal_object_id", "Service principal not found for resource (Object ID: %q)", resourceId)
}
return tf.ErrorDiagF(err, "Could not retrieve service principal for resource (Object ID: %q)", resourceId)
}
properties := msgraph.AppRoleAssignment{

properties := stable.AppRoleAssignment{
AppRoleId: pointer.To(appRoleId),
PrincipalId: pointer.To(principalId),
ResourceId: pointer.To(resourceId),
PrincipalId: nullable.Value(principalId),
ResourceId: nullable.Value(resourceId),
}

appRoleAssignment, _, err := client.Assign(ctx, properties)
options := approleassignedto.CreateAppRoleAssignedToOperationOptions{
RetryFunc: func(resp *http.Response, o *odata.OData) (bool, error) {
if response.WasNotFound(resp) {
return true, nil
} else if response.WasBadRequest(resp) && o != nil && o.Error != nil {
return o.Error.Match("Not a valid reference update"), nil
}
return false, nil
},
}

resp, err := client.CreateAppRoleAssignedTo(ctx, stable.NewServicePrincipalID(resourceId), properties, options)
if err != nil {
return tf.ErrorDiagF(err, "Could not create app role assignment")
}

appRoleAssignment := resp.Model
if appRoleAssignment == nil {
return tf.ErrorDiagF(errors.New("model was nil"), "Could not create app role assignment")
}

if appRoleAssignment.Id == nil || *appRoleAssignment.Id == "" {
return tf.ErrorDiagF(errors.New("ID returned for app role assignment is nil"), "Bad API response")
}

if appRoleAssignment.ResourceId == nil || *appRoleAssignment.ResourceId == "" {
if appRoleAssignment.ResourceId.IsNull() || appRoleAssignment.ResourceId.GetOrZero() == "" {
return tf.ErrorDiagF(errors.New("Resource ID returned for app role assignment is nil"), "Bad API response")
}

id := parse.NewAppRoleAssignmentID(*appRoleAssignment.ResourceId, *appRoleAssignment.Id)
id := parse.NewAppRoleAssignmentID(appRoleAssignment.ResourceId.GetOrZero(), *appRoleAssignment.Id)
d.SetId(id.String())

return appRoleAssignmentResourceRead(ctx, d, meta)
Expand All @@ -125,58 +146,50 @@ func appRoleAssignmentResourceCreate(ctx context.Context, d *pluginsdk.ResourceD
func appRoleAssignmentResourceRead(ctx context.Context, d *pluginsdk.ResourceData, meta interface{}) pluginsdk.Diagnostics {
client := meta.(*clients.Client).AppRoleAssignments.AppRoleAssignedToClient

id, err := parse.AppRoleAssignmentID(d.Id())
resourceId, err := parse.AppRoleAssignmentID(d.Id())
if err != nil {
return tf.ErrorDiagPathF(err, "id", "Parsing app role assignment with ID %q", d.Id())
}

query := odata.Query{Filter: fmt.Sprintf("id eq '%s'", id.AssignmentId)}
appRoleAssignments, status, err := client.List(ctx, id.ResourceId, query)
id := stable.NewServicePrincipalIdAppRoleAssignedToID(resourceId.ResourceId, resourceId.AssignmentId)

resp, err := client.GetAppRoleAssignedTo(ctx, id, approleassignedto.DefaultGetAppRoleAssignedToOperationOptions())
if err != nil {
if status == http.StatusNotFound {
log.Printf("[DEBUG] Resource Service Principal %q was not found - removing from state!", id.ResourceId)
if response.WasNotFound(resp.HttpResponse) {
log.Printf("[DEBUG] %s was not found - removing from state!", id)
d.SetId("")
return nil
}
return tf.ErrorDiagF(err, "retrieving app role assignments for resource with object ID: %q", id.ResourceId)
}
if appRoleAssignments == nil {
return tf.ErrorDiagF(errors.New("appRoleAssignments was nil"), "retrieving app role assignments for resource with object ID: %q", id.ResourceId)
return tf.ErrorDiagF(err, "retrieving %s", id)
}

var appRoleAssignment *msgraph.AppRoleAssignment
for _, assignment := range *appRoleAssignments {
if assignment.Id != nil && *assignment.Id == id.AssignmentId {
appRoleAssignment = &assignment
break
}
}
appRoleAssignment := resp.Model
if appRoleAssignment == nil {
log.Printf("[DEBUG] App Role Assignment %q for Resource %q was not found - removing from state!", id.AssignmentId, id.ResourceId)
d.SetId("")
return nil
return tf.ErrorDiagF(errors.New("model was nil"), "retrieving %s", id)
}

tf.Set(d, "app_role_id", appRoleAssignment.AppRoleId)
tf.Set(d, "principal_display_name", appRoleAssignment.PrincipalDisplayName)
tf.Set(d, "principal_object_id", appRoleAssignment.PrincipalId)
tf.Set(d, "principal_type", appRoleAssignment.PrincipalType)
tf.Set(d, "resource_display_name", appRoleAssignment.ResourceDisplayName)
tf.Set(d, "resource_object_id", appRoleAssignment.ResourceId)
tf.Set(d, "principal_display_name", appRoleAssignment.PrincipalDisplayName.GetOrZero())
tf.Set(d, "principal_object_id", appRoleAssignment.PrincipalId.GetOrZero())
tf.Set(d, "principal_type", appRoleAssignment.PrincipalType.GetOrZero())
tf.Set(d, "resource_display_name", appRoleAssignment.ResourceDisplayName.GetOrZero())
tf.Set(d, "resource_object_id", appRoleAssignment.ResourceId.GetOrZero())

return nil
}

func appRoleAssignmentResourceDelete(ctx context.Context, d *pluginsdk.ResourceData, meta interface{}) pluginsdk.Diagnostics {
client := meta.(*clients.Client).AppRoleAssignments.AppRoleAssignedToClient

id, err := parse.AppRoleAssignmentID(d.Id())
resourceId, err := parse.AppRoleAssignmentID(d.Id())
if err != nil {
return tf.ErrorDiagPathF(err, "id", "Parsing app role assignment with ID %q", d.Id())
}

if status, err := client.Remove(ctx, id.ResourceId, id.AssignmentId); err != nil {
return tf.ErrorDiagPathF(err, "id", "Deleting app role assignment for resource %q with ID %q, got status %d", id.ResourceId, id.AssignmentId, status)
id := stable.NewServicePrincipalIdAppRoleAssignedToID(resourceId.ResourceId, resourceId.AssignmentId)

if _, err = client.DeleteAppRoleAssignedTo(ctx, id, approleassignedto.DefaultDeleteAppRoleAssignedToOperationOptions()); err != nil {
return tf.ErrorDiagPathF(err, "id", "Deleting %s: %v", id, err)
}

return nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ package approleassignments_test
import (
"context"
"fmt"
"net/http"
"testing"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-sdk/sdk/odata"
"github.com/hashicorp/go-azure-helpers/lang/response"
"github.com/hashicorp/go-azure-sdk/microsoft-graph/common-types/stable"
"github.com/hashicorp/go-azure-sdk/microsoft-graph/serviceprincipals/stable/approleassignedto"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"github.com/hashicorp/terraform-provider-azuread/internal/acceptance"
"github.com/hashicorp/terraform-provider-azuread/internal/acceptance/check"
Expand Down Expand Up @@ -98,34 +99,28 @@ func TestAccAppRoleAssignment_userForTenantApp(t *testing.T) {

func (r AppRoleAssignmentResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) {
client := clients.AppRoleAssignments.AppRoleAssignedToClient
client.BaseClient.DisableRetries = true
defer func() { client.BaseClient.DisableRetries = false }()

id, err := parse.AppRoleAssignmentID(state.ID)
resourceId, err := parse.AppRoleAssignmentID(state.ID)
if err != nil {
return nil, fmt.Errorf("parsing App Role Assignment ID: %v", err)
}

query := odata.Query{Filter: fmt.Sprintf("id eq '%s'", id.AssignmentId)}
appRoleAssignments, status, err := client.List(ctx, id.ResourceId, query)
id := stable.NewServicePrincipalIdAppRoleAssignedToID(resourceId.ResourceId, resourceId.AssignmentId)

resp, err := client.GetAppRoleAssignedTo(ctx, id, approleassignedto.DefaultGetAppRoleAssignedToOperationOptions())
if err != nil {
if status == http.StatusNotFound {
return nil, fmt.Errorf("Resource Service Principal with ID %q does not exist", id.ResourceId)
if response.WasNotFound(resp.HttpResponse) {
return pointer.To(false), nil
}
return nil, fmt.Errorf("failed to retrieve Resource Service Principal with ID %q: %+v", id.ResourceId, err)
}

if appRoleAssignments == nil {
return nil, fmt.Errorf("failed to retrieve App Role Assignments for Resource with ID %q: appRoleAssignments was nil", id.ResourceId)
return nil, fmt.Errorf("failed to retrieve %s: %+v", id, err)
}

for _, assignment := range *appRoleAssignments {
if assignment.Id != nil && *assignment.Id == id.AssignmentId {
return pointer.To(true), nil
}
appRoleAssignment := resp.Model
if appRoleAssignment == nil {
return nil, fmt.Errorf("retrieving %s: model was nil", id)
}

return pointer.To(false), nil
return pointer.To(true), nil
}

func (AppRoleAssignmentResource) servicePrincipalForMsGraph(data acceptance.TestData) string {
Expand Down
27 changes: 17 additions & 10 deletions internal/services/approleassignments/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,31 @@
package client

import (
"github.com/hashicorp/go-azure-sdk/microsoft-graph/serviceprincipals/stable/approleassignedto"
"github.com/hashicorp/go-azure-sdk/microsoft-graph/serviceprincipals/stable/serviceprincipal"
"github.com/hashicorp/terraform-provider-azuread/internal/common"
"github.com/manicminer/hamilton/msgraph"
)

type Client struct {
AppRoleAssignedToClient *msgraph.AppRoleAssignedToClient
ServicePrincipalsClient *msgraph.ServicePrincipalsClient
AppRoleAssignedToClient *approleassignedto.AppRoleAssignedToClient
ServicePrincipalClient *serviceprincipal.ServicePrincipalClient
}

func NewClient(o *common.ClientOptions) *Client {
appRoleAssignedToClient := msgraph.NewAppRoleAssignedToClient()
o.ConfigureClient(&appRoleAssignedToClient.BaseClient)
func NewClient(o *common.ClientOptions) (*Client, error) {
appRoleAssignedToClient, err := approleassignedto.NewAppRoleAssignedToClientWithBaseURI(o.Environment.MicrosoftGraph)
if err != nil {
return nil, err
}
o.Configure(appRoleAssignedToClient.Client)

servicePrincipalsClient := msgraph.NewServicePrincipalsClient()
o.ConfigureClient(&servicePrincipalsClient.BaseClient)
servicePrincipalClient, err := serviceprincipal.NewServicePrincipalClientWithBaseURI(o.Environment.MicrosoftGraph)
if err != nil {
return nil, err
}
o.Configure(servicePrincipalClient.Client)

return &Client{
AppRoleAssignedToClient: appRoleAssignedToClient,
ServicePrincipalsClient: servicePrincipalsClient,
}
ServicePrincipalClient: servicePrincipalClient,
}, nil
}
2 changes: 1 addition & 1 deletion internal/services/approleassignments/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

package approleassignments

import "github.com/hashicorp/terraform-provider-azuread/internal/tf/pluginsdk"
import "github.com/hashicorp/terraform-provider-azuread/internal/helpers/tf/pluginsdk"

type Registration struct{}

Expand Down

0 comments on commit 6322617

Please sign in to comment.