Skip to content

Commit

Permalink
add azurerm_iotcentral_organization (#23132)
Browse files Browse the repository at this point in the history
* add azurerm_iotcentral_organization

* make terrafmt

* make generate

* fix import path in iotcentral_organization_resource.go

* use environments.Api in iotcentral/client/client.go

* refactor NestedItemId to OrganizationID

* Update website/docs/r/iotcentral_organization.html.markdown

Co-authored-by: Tom Harvey <tombuildsstuff@users.noreply.github.com>

* rename parent property to parent_organization_id & add ForceNew

* expand organizationId validation

* add regex patern in validateOrganizationId() error output

* improve OrganizationID.String() description

* refactor resourceId & make use of iotcentral_application_id

---------

Co-authored-by: Tom Harvey <tombuildsstuff@users.noreply.github.com>
Co-authored-by: kt <kt@katbyte.me>
  • Loading branch information
3 people authored Feb 9, 2024
1 parent 325f61b commit c71cc87
Show file tree
Hide file tree
Showing 34 changed files with 22,377 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/labeler-issue-triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ service/hybrid-compute:
- '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_(arc_machine\W+|arc_machine_extension\W+|arc_private_link_scope\W+|hybrid_compute_machine)((.|\n)*)###'

service/iot-central:
- '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_iotcentral_application((.|\n)*)###'
- '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_iotcentral_((.|\n)*)###'

service/iot-hub:
- '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_iothub((.|\n)*)###'
Expand Down
33 changes: 31 additions & 2 deletions internal/services/iotcentral/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,52 @@
package client

import (
"context"
"fmt"

"github.com/Azure/go-autorest/autorest"
"github.com/hashicorp/go-azure-sdk/resource-manager/iotcentral/2021-11-01-preview/apps"
authWrapper "github.com/hashicorp/go-azure-sdk/sdk/auth/autorest"
"github.com/hashicorp/go-azure-sdk/sdk/environments"
"github.com/hashicorp/terraform-provider-azurerm/internal/common"
dataplane "github.com/tombuildsstuff/kermit/sdk/iotcentral/2022-10-31-preview/iotcentral"
)

type Client struct {
AppsClient *apps.AppsClient
AppsClient *apps.AppsClient
authorizerFunc common.ApiAuthorizerFunc
configureClientFunc func(c *autorest.Client, authorizer autorest.Authorizer)
Endpoint environments.Api
}

func NewClient(o *common.ClientOptions) (*Client, error) {
appsClient, err := apps.NewAppsClientWithBaseURI(o.Environment.ResourceManager)
if err != nil {
return nil, fmt.Errorf("building Apps Client: %+v", err)
}

o.Configure(appsClient.Client, o.Authorizers.ResourceManager)

return &Client{
AppsClient: appsClient,
AppsClient: appsClient,
authorizerFunc: o.Authorizers.AuthorizerFunc,
configureClientFunc: o.ConfigureClient,
Endpoint: o.Environment.IoTCentral,
}, nil
}

func (c *Client) OrganizationsClient(ctx context.Context, subdomain string) (*dataplane.OrganizationsClient, 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.NewOrganizationsClient(subdomain)
c.configureClientFunc(&client.Client, authWrapper.AutorestAuthorizer(iotCentralAuth))

return &client, nil
}
261 changes: 261 additions & 0 deletions internal/services/iotcentral/iotcentral_organization_resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
// 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 IotCentralOrganizationResource struct{}

var (
_ sdk.ResourceWithUpdate = IotCentralOrganizationResource{}
)

type IotCentralOrganizationModel struct {
IotCentralApplicationId string `tfschema:"iotcentral_application_id"`
OrganizationId string `tfschema:"organization_id"`
DisplayName string `tfschema:"display_name"`
ParentOrganizationId string `tfschema:"parent_organization_id"`
}

func (r IotCentralOrganizationResource) Arguments() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{
"iotcentral_application_id": {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: apps.ValidateIotAppID,
},
"organization_id": {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validate.OrganizationOrganizationID,
},
"display_name": {
Type: pluginsdk.TypeString,
Required: true,
},
"parent_organization_id": {
Type: pluginsdk.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validate.OrganizationOrganizationID,
},
}
}

func (r IotCentralOrganizationResource) Attributes() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{}
}

func (r IotCentralOrganizationResource) ResourceType() string {
return "azurerm_iotcentral_organization"
}

func (r IotCentralOrganizationResource) ModelObject() interface{} {
return &IotCentralOrganizationModel{}
}

func (r IotCentralOrganizationResource) IDValidationFunc() pluginsdk.SchemaValidateFunc {
return validate.OrganizationID
}

func (r IotCentralOrganizationResource) Create() sdk.ResourceFunc {
return sdk.ResourceFunc{
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.IoTCentral
var state IotCentralOrganizationModel
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)
}

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

model := dataplane.Organization{
DisplayName: &state.DisplayName,
}

if state.ParentOrganizationId != "" {
model.Parent = &state.ParentOrganizationId
}

org, err := orgClient.Create(ctx, state.OrganizationId, model)
if err != nil {
return fmt.Errorf("creating %s: %+v", state.OrganizationId, err)
}

orgId := parse.NewOrganizationID(appId.SubscriptionId, appId.ResourceGroupName, appId.IotAppName, *org.ID)

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

func (r IotCentralOrganizationResource) Read() sdk.ResourceFunc {
return sdk.ResourceFunc{
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.IoTCentral
id, err := parse.OrganizationID(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.OrganizationsClient(ctx, *app.Model.Properties.Subdomain)
if err != nil {
return fmt.Errorf("creating organization client: %+v", err)
}

org, err := orgClient.Get(ctx, id.Name)
if err != nil {
if org.ID == nil || *org.ID == "" {
return metadata.MarkAsGone(id)
}

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

state := IotCentralOrganizationModel{
IotCentralApplicationId: appId.ID(),
OrganizationId: id.Name,
DisplayName: *org.DisplayName,
}

if org.Parent != nil {
state.ParentOrganizationId = *org.Parent
}

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

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

id, err := parse.OrganizationID(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.OrganizationsClient(ctx, *app.Model.Properties.Subdomain)
if err != nil {
return fmt.Errorf("creating organization client: %+v", err)
}

existing, err := orgClient.Get(ctx, id.Name)
if err != nil {
if existing.ID == nil || *existing.ID == "" {
return metadata.MarkAsGone(id)
}

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

if metadata.ResourceData.HasChange("display_name") {
existing.DisplayName = &state.DisplayName
}

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

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

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

id, err := parse.OrganizationID(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.OrganizationsClient(ctx, *app.Model.Properties.Subdomain)
if err != nil {
return fmt.Errorf("creating organization 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

0 comments on commit c71cc87

Please sign in to comment.