Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add azurerm_iotcentral_user #24911

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions internal/services/iotcentral/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,19 @@ func (c *Client) OrganizationsClient(ctx context.Context, subdomain string) (*da

return &client, nil
}

func (c *Client) UsersClient(ctx context.Context, subdomain string) (*dataplane.UsersClient, error) {
if !c.Endpoint.Available() {
return nil, fmt.Errorf("unable to build SDK Client since IoTCentral is not available in this Azure Environment")
}

iotCentralAuth, err := c.authorizerFunc(c.Endpoint)
if err != nil {
return nil, fmt.Errorf("obtaining auth token for %q: %+v", c.Endpoint.Name(), err)
}

client := dataplane.NewUsersClient(subdomain)
c.configureClientFunc(&client.Client, authWrapper.AutorestAuthorizer(iotCentralAuth))

return &client, nil
}
309 changes: 309 additions & 0 deletions internal/services/iotcentral/iotcentral_group_user_resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package iotcentral

import (
"context"
"fmt"
"time"

"github.com/hashicorp/go-azure-sdk/resource-manager/iotcentral/2021-11-01-preview/apps"
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/iotcentral/parse"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/iotcentral/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
dataplane "github.com/tombuildsstuff/kermit/sdk/iotcentral/2022-10-31-preview/iotcentral"
)

type IotCentralGroupUserResource struct{}

var (
_ sdk.ResourceWithUpdate = IotCentralGroupUserResource{}
)

type IotCentralGroupUserModel struct {
IotCentralApplicationId string `tfschema:"iotcentral_application_id"`
UserId string `tfschema:"user_id"`
Type string `tfschema:"type"`
TenantId string `tfschema:"tenant_id"`
ObjectId string `tfschema:"object_id"`
Role []Role `tfschema:"role"`
}

func (r IotCentralGroupUserResource) Arguments() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{
"iotcentral_application_id": {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: apps.ValidateIotAppID,
},
"user_id": {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validate.UserUserID,
},
"tenant_id": {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
},
"object_id": {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
},
"role": {
Type: pluginsdk.TypeList,
Required: true,
Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
"role_id": {
Type: pluginsdk.TypeString,
Required: true,
},
"organization_id": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validate.OrganizationOrganizationID,
},
},
},
},
}
}

func (r IotCentralGroupUserResource) Attributes() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{
"type": {
Type: pluginsdk.TypeString,
Computed: true,
},
}
}

func (r IotCentralGroupUserResource) ResourceType() string {
return "azurerm_iotcentral_group_user"
}

func (r IotCentralGroupUserResource) ModelObject() interface{} {
return &IotCentralGroupUserModel{}
}

func (IotCentralGroupUserResource) IDValidationFunc() pluginsdk.SchemaValidateFunc {
return validate.UserID
}

func (u IotCentralGroupUserModel) AsGroupUser() dataplane.ADGroupUser {
return dataplane.ADGroupUser{
TenantID: &u.TenantId,
ObjectID: &u.ObjectId,
ID: &u.UserId,
Type: dataplane.TypeBasicUserTypeAdGroup,
Roles: ConvertToRoleAssignments(u.Role),
}
}

func TryValidateGroupUserExistence(user dataplane.BasicUser) (string, bool) {
if userValue, ok := user.AsADGroupUser(); ok {
return *userValue.ID, true
}
return "", false
}

func (r IotCentralGroupUserResource) Create() sdk.ResourceFunc {
return sdk.ResourceFunc{
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.IoTCentral
var state IotCentralGroupUserModel
if err := metadata.Decode(&state); err != nil {
return err
}

appId, err := apps.ParseIotAppID(state.IotCentralApplicationId)
if err != nil {
return err
}

app, err := client.AppsClient.Get(ctx, *appId)
if err != nil || app.Model == nil {
return fmt.Errorf("checking for the presence of existing %q: %+v", appId, err)
}

userClient, err := client.UsersClient(ctx, *app.Model.Properties.Subdomain)
if err != nil {
return fmt.Errorf("creating user client: %+v", err)
}

userToCreate := state.AsGroupUser()

user, err := userClient.Create(ctx, state.UserId, userToCreate)
if err != nil {
return fmt.Errorf("creating %s: %+v", state.UserId, err)
}

_, isValid := TryValidateGroupUserExistence(user.Value)
if !isValid {
return fmt.Errorf("unable to validate existence of user: id = %+v, type = Group after creating user: %+v", state.UserId, userToCreate)
}

id := parse.NewUserID(appId.SubscriptionId, appId.ResourceGroupName, appId.IotAppName, state.UserId)

metadata.SetID(id)
return nil
},
Timeout: 30 * time.Minute,
}
}

func (r IotCentralGroupUserResource) Read() sdk.ResourceFunc {
return sdk.ResourceFunc{
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.IoTCentral
id, err := parse.UserID(metadata.ResourceData.Id())
if err != nil {
return err
}

appId := apps.NewIotAppID(id.SubscriptionId, id.ResourceGroup, id.IotAppName)
if err != nil {
return err
}

app, err := client.AppsClient.Get(ctx, appId)
if err != nil || app.Model == nil {
return metadata.MarkAsGone(id)
}

userClient, err := client.UsersClient(ctx, *app.Model.Properties.Subdomain)
if err != nil {
return fmt.Errorf("creating user client: %+v", err)
}

user, err := userClient.Get(ctx, id.Name)
_, isValid := TryValidateGroupUserExistence(user.Value)
if err != nil {
if !isValid {
return metadata.MarkAsGone(id)
}

return fmt.Errorf("retrieving %s: %+v", *id, err)
}

groupUser, isValid := user.Value.AsADGroupUser()
if !isValid {
return fmt.Errorf("unable to convert user to type GroupUser")
}

var state = IotCentralGroupUserModel{
IotCentralApplicationId: appId.ID(),
UserId: id.Name,
Type: "Group",
TenantId: *groupUser.TenantID,
ObjectId: *groupUser.ObjectID,
Role: ConvertFromRoleAssignments(groupUser.Roles),
}

return metadata.Encode(&state)
},
Timeout: 5 * time.Minute,
}
}

func (r IotCentralGroupUserResource) Update() sdk.ResourceFunc {
return sdk.ResourceFunc{
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.IoTCentral
var state IotCentralGroupUserModel
if err := metadata.Decode(&state); err != nil {
return err
}

id, err := parse.UserID(metadata.ResourceData.Id())
if err != nil {
return err
}

appId := apps.NewIotAppID(id.SubscriptionId, id.ResourceGroup, id.IotAppName)
if err != nil {
return err
}

app, err := client.AppsClient.Get(ctx, appId)
if err != nil || app.Model == nil {
return metadata.MarkAsGone(id)
}

userClient, err := client.UsersClient(ctx, *app.Model.Properties.Subdomain)
if err != nil {
return fmt.Errorf("creating user client: %+v", err)
}

existing, err := userClient.Get(ctx, id.Name)
_, isValid := TryValidateGroupUserExistence(existing.Value)
if err != nil {
if !isValid {
return metadata.MarkAsGone(id)
}

return fmt.Errorf("retrieving %s: %+v", *id, err)
}

groupUser, _ := existing.Value.AsADGroupUser()

if metadata.ResourceData.HasChange("role") {
groupUser.Roles = ConvertToRoleAssignments(state.Role)
}

_, err = userClient.Update(ctx, *groupUser.ID, groupUser, "*")
if err != nil {
return fmt.Errorf("updating %s: %+v", id, err)
}

return nil
},
Timeout: 30 * time.Minute,
}
}

func (r IotCentralGroupUserResource) Delete() sdk.ResourceFunc {
return sdk.ResourceFunc{
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.IoTCentral
var state IotCentralGroupUserModel
if err := metadata.Decode(&state); err != nil {
return err
}

id, err := parse.UserID(metadata.ResourceData.Id())
if err != nil {
return err
}

appId := apps.NewIotAppID(id.SubscriptionId, id.ResourceGroup, id.IotAppName)
if err != nil {
return err
}

app, err := client.AppsClient.Get(ctx, appId)
if err != nil || app.Model == nil {
return metadata.MarkAsGone(id)
}

orgClient, err := client.UsersClient(ctx, *app.Model.Properties.Subdomain)
if err != nil {
return fmt.Errorf("creating user client: %+v", err)
}

_, err = orgClient.Remove(ctx, id.Name)
if err != nil {
return fmt.Errorf("deleting %s: %+v", id, err)
}

return nil
},
Timeout: 30 * time.Minute,
}
}
Loading
Loading