Skip to content

Commit

Permalink
CDPCP-9629 ID Broker resource shoudl detect if the environment is del…
Browse files Browse the repository at this point in the history
…eted
  • Loading branch information
daszabo committed Nov 8, 2023
1 parent cdf2374 commit 89abd66
Show file tree
Hide file tree
Showing 6 changed files with 750 additions and 56 deletions.
23 changes: 23 additions & 0 deletions .mockery.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## Copyright 2023 Cloudera. All Rights Reserved.
#
# This file is licensed under the Apache License Version 2.0 (the "License").
# You may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
#
# This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
# OF ANY KIND, either express or implied. Refer to the License for the specific
# permissions and limitations governing your use of the file.

quiet: False
keeptree: True
disable-version-string: True
with-expecter: True
mockname: "{{.InterfaceName}}"
filename: "{{.MockName}}.go"
outpkg: mocks
packages:
github.com/cloudera/terraform-provider-cdp/cdp-sdk-go/gen/environments/client/operations:
interfaces:
ClientService:
config:
mockname: "MockEnvironment{{.InterfaceName}}"
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,26 @@ Pull requests are expected to include appropriate updates to the [change log](./
make
```

### Unit testing

We are using github.com/vektra/mockery to generate mock interfaces for unit tests. To generate a new mock interface:
1. Install the mockery cli tool:
```
brew install mockery
```
2. Add the package/interface to the mockery.yaml configuration file:
```
github.com/cloudera/terraform-provider-cdp/cdp-sdk-go/gen/environments/client/operations:
interfaces:
ClientService:
config:
mockname: "MockEnvironment{{.InterfaceName}}"
```
3. Issue the mockery command in the repository to generate the mock interfaces:
```
$ mockery
```

### Execute example terraform

```
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ require (
github.com/armon/go-radix v1.0.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/bgentry/speakeasy v0.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
Expand Down Expand Up @@ -84,6 +85,7 @@ require (
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/posener/complete v1.2.3 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/russross/blackfriday v1.6.0 // indirect
Expand All @@ -93,6 +95,7 @@ require (
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.16.0 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/stretchr/testify v1.8.4 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/toqueteos/webbrowser v1.2.0 // indirect
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1Fof
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
Expand Down
149 changes: 93 additions & 56 deletions resources/environments/resource_id_broker_mappings.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"context"

"github.com/cloudera/terraform-provider-cdp/cdp-sdk-go/cdp"
"github.com/cloudera/terraform-provider-cdp/cdp-sdk-go/gen/environments/client"
"github.com/cloudera/terraform-provider-cdp/cdp-sdk-go/gen/environments/client/operations"
environmentsmodels "github.com/cloudera/terraform-provider-cdp/cdp-sdk-go/gen/environments/models"
"github.com/cloudera/terraform-provider-cdp/utils"
Expand All @@ -24,6 +25,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
)
Expand All @@ -33,6 +35,63 @@ var (
emptyMappings = true
)

var IDBrokerMappingSchema = schema.Schema{
MarkdownDescription: "To enable your CDP user to utilize the central authentication features CDP provides and to exchange credentials for AWS or Azure access tokens, you have to map this CDP user to the correct IAM role or Azure Managed Service Identity (MSI).",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"data_access_role": schema.StringAttribute{
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"environment_name": schema.StringAttribute{
Required: true,
},
"environment_crn": schema.StringAttribute{
Required: true,
},
"mappings": schema.SetNestedAttribute{
Optional: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"accessor_crn": schema.StringAttribute{
Required: true,
},
"role": schema.StringAttribute{
Required: true,
},
},
},
},
"ranger_audit_role": schema.StringAttribute{
Required: true,
},
"ranger_cloud_access_authorizer_role": schema.StringAttribute{
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"set_empty_mappings": schema.BoolAttribute{
Optional: true,
},
"mappings_version": schema.Int64Attribute{
Computed: true,
PlanModifiers: []planmodifier.Int64{
int64planmodifier.UseStateForUnknown(),
},
},
},
}

type idBrokerMappingsResource struct {
client *cdp.Client
}
Expand Down Expand Up @@ -91,62 +150,7 @@ func toSetIDBrokerMappingsRequest(ctx context.Context, model *idBrokerMappingsRe
}

func (r *idBrokerMappingsResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "To enable your CDP user to utilize the central authentication features CDP provides and to exchange credentials for AWS or Azure access tokens, you have to map this CDP user to the correct IAM role or Azure Managed Service Identity (MSI).",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"data_access_role": schema.StringAttribute{
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"environment_name": schema.StringAttribute{
Required: true,
},
"environment_crn": schema.StringAttribute{
Required: true,
},
"mappings": schema.SetNestedAttribute{
Optional: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"accessor_crn": schema.StringAttribute{
Required: true,
},
"role": schema.StringAttribute{
Required: true,
},
},
},
},
"ranger_audit_role": schema.StringAttribute{
Required: true,
},
"ranger_cloud_access_authorizer_role": schema.StringAttribute{
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"set_empty_mappings": schema.BoolAttribute{
Optional: true,
},
"mappings_version": schema.Int64Attribute{
Computed: true,
PlanModifiers: []planmodifier.Int64{
int64planmodifier.UseStateForUnknown(),
},
},
},
}
resp.Schema = IDBrokerMappingSchema
}

func (r *idBrokerMappingsResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
Expand Down Expand Up @@ -200,6 +204,15 @@ func isSetIDBEnvNotFoundError(err error) bool {
return false
}

func queryEnvironment(ctx context.Context, client *client.Environments, envName string, state *idBrokerMappingsResourceModel) error {
envParams := operations.NewDescribeEnvironmentParamsWithContext(ctx)
envParams.WithInput(&environmentsmodels.DescribeEnvironmentRequest{
EnvironmentName: &envName,
})
_, err := client.Operations.DescribeEnvironment(envParams)
return err
}

func (r *idBrokerMappingsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var state idBrokerMappingsResourceModel
diags := req.State.Get(ctx, &state)
Expand All @@ -209,6 +222,12 @@ func (r *idBrokerMappingsResource) Read(ctx context.Context, req resource.ReadRe
}

client := r.client.Environments

if err := queryEnvironment(ctx, client, state.EnvironmentName.ValueString(), &state); isEnvNotFoundError(err) {
removeResourceFromState(ctx, &resp.Diagnostics, &resp.State, state)
return
}

params := operations.NewGetIDBrokerMappingsParamsWithContext(ctx)
params.WithInput(&environmentsmodels.GetIDBrokerMappingsRequest{
EnvironmentName: state.EnvironmentName.ValueStringPointer(),
Expand Down Expand Up @@ -239,6 +258,14 @@ func (r *idBrokerMappingsResource) Read(ctx context.Context, req resource.ReadRe
}
}

func removeResourceFromState(ctx context.Context, diag *diag.Diagnostics, state *tfsdk.State, model idBrokerMappingsResourceModel) {
diag.AddWarning("Resource not found on provider", "Environment not found, removing ID Broker mapping from state.")
tflog.Warn(ctx, "Environment not found, removing ID Broker mapping from state", map[string]interface{}{
"id": model.ID.ValueString(),
})
state.RemoveResource(ctx)
}

func toIdBrokerMappingsResourceModel(ctx context.Context, mapping *environmentsmodels.GetIDBrokerMappingsResponse, out *idBrokerMappingsResourceModel, diags *diag.Diagnostics) {
out.DataAccessRole = types.StringPointerValue(mapping.DataAccessRole)
out.MappingsVersion = types.Int64PointerValue(mapping.MappingsVersion)
Expand Down Expand Up @@ -281,6 +308,11 @@ func (r *idBrokerMappingsResource) Update(ctx context.Context, req resource.Upda

client := r.client.Environments

if err := queryEnvironment(ctx, client, state.EnvironmentName.ValueString(), &state); isEnvNotFoundError(err) {
removeResourceFromState(ctx, &resp.Diagnostics, &resp.State, state)
return
}

params := operations.NewSetIDBrokerMappingsParamsWithContext(ctx)
params.WithInput(toSetIDBrokerMappingsRequest(ctx, &state, &resp.Diagnostics))
responseOk, err := client.Operations.SetIDBrokerMappings(params)
Expand Down Expand Up @@ -319,6 +351,11 @@ func (r *idBrokerMappingsResource) Delete(ctx context.Context, req resource.Dele

client := r.client.Environments

if err := queryEnvironment(ctx, client, state.EnvironmentName.ValueString(), &state); isEnvNotFoundError(err) {
removeResourceFromState(ctx, &resp.Diagnostics, &resp.State, state)
return
}

params := operations.NewSetIDBrokerMappingsParamsWithContext(ctx)
input := &environmentsmodels.SetIDBrokerMappingsRequest{}
input.EnvironmentName = state.EnvironmentName.ValueStringPointer()
Expand Down
Loading

0 comments on commit 89abd66

Please sign in to comment.