diff --git a/docs/resources/environments_user_sync.md b/docs/resources/environments_user_sync.md new file mode 100644 index 00000000..8c2d9e9d --- /dev/null +++ b/docs/resources/environments_user_sync.md @@ -0,0 +1,39 @@ +--- +page_title: "cdp_environments_user_sync Resource - terraform-provider-cdp" +subcategory: "environments" +description: |- + Synchronizes environments with all users and groups state with CDP. +--- + +# cdp_environments_user_sync (Resource) + +Synchronizes environments with all users and groups state with CDP. + +## Example Usage + +```terraform +## Copyright 2024 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. + +resource "cdp_environments_user_sync" "example-user_sync" { + environment_names = ["example-cdp-environment-1", "example-cdp-environment-2"] +} +``` + + +## Schema + +### Optional + +- `environment_names` (Set of String) List of environments to be synced. If not present, all environments will be synced. + +### Read-Only + +- `id` (String) The ID of this resource. \ No newline at end of file diff --git a/examples/resources/cdp_environments_user_sync/resource.tf b/examples/resources/cdp_environments_user_sync/resource.tf new file mode 100644 index 00000000..54b749b6 --- /dev/null +++ b/examples/resources/cdp_environments_user_sync/resource.tf @@ -0,0 +1,13 @@ +## Copyright 2024 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. + +resource "cdp_environments_user_sync" "example-user_sync" { + environment_names = ["example-cdp-environment-1", "example-cdp-environment-2"] +} diff --git a/provider/provider.go b/provider/provider.go index a3f7f5f4..2e385dbb 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -227,6 +227,7 @@ func (p *CdpProvider) Resources(_ context.Context) []func() resource.Resource { environments.NewAwsCredentialResource, environments.NewAwsEnvironmentResource, environments.NewIDBrokerMappingsResource, + environments.NewUserSyncResource, environments.NewAzureCredentialResource, environments.NewAzureEnvironmentResource, environments.NewAzureImageTermsResource, diff --git a/provider/provider_test.go b/provider/provider_test.go index 18197622..7459af9f 100644 --- a/provider/provider_test.go +++ b/provider/provider_test.go @@ -613,6 +613,7 @@ func TestCdpProvider_Resources(t *testing.T) { environments.NewAwsCredentialResource, environments.NewAwsEnvironmentResource, environments.NewIDBrokerMappingsResource, + environments.NewUserSyncResource, environments.NewAzureCredentialResource, environments.NewAzureEnvironmentResource, environments.NewGcpEnvironmentResource, diff --git a/resources/environments/resource_user_sync.go b/resources/environments/resource_user_sync.go new file mode 100644 index 00000000..30866535 --- /dev/null +++ b/resources/environments/resource_user_sync.go @@ -0,0 +1,166 @@ +// Copyright 2024 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. + +package environments + +import ( + "context" + + "github.com/cloudera/terraform-provider-cdp/cdp-sdk-go/cdp" + "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" + "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +var ( + _ resource.Resource = &userSyncResource{} +) + +var userSyncSchema = schema.Schema{ + MarkdownDescription: "Synchronizes environments with all users and groups state with CDP.", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "environment_names": schema.SetAttribute{ + MarkdownDescription: "List of environments to be synced. If not present, all environments will be synced.", + ElementType: types.StringType, + Optional: true, + }, + }, +} + +type userSyncResource struct { + client *cdp.Client +} + +func NewUserSyncResource() resource.Resource { + return &userSyncResource{} +} + +func (r *userSyncResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_environments_user_sync" +} + +type userSyncResourceModel struct { + ID types.String `tfsdk:"id"` + + EnvironmentNames types.Set `tfsdk:"environment_names"` +} + +func toSyncAllUsersRequest(ctx context.Context, model *userSyncResourceModel, diag *diag.Diagnostics) *environmentsmodels.SyncAllUsersRequest { + req := &environmentsmodels.SyncAllUsersRequest{} + req.EnvironmentNames = utils.FromSetValueToStringList(model.EnvironmentNames) + return req +} + +func (r *userSyncResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = userSyncSchema +} + +func (r *userSyncResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + r.client = utils.GetCdpClientForResource(req, resp) +} + +func (r *userSyncResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var state userSyncResourceModel + diags := req.Plan.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + tflog.Error(ctx, "Got Error while trying to set plan") + return + } + + client := r.client.Environments + + params := operations.NewSyncAllUsersParamsWithContext(ctx) + params.WithInput(toSyncAllUsersRequest(ctx, &state, &resp.Diagnostics)) + _, err := client.Operations.SyncAllUsers(params) + if err != nil { + if isSyncAllUsersNotFoundError(err) { + resp.Diagnostics.AddError( + "Error in sync all users", + "An environment not found: "+state.EnvironmentNames.String(), + ) + return + } + utils.AddEnvironmentDiagnosticsError(err, &resp.Diagnostics, "sync all users") + return + } + + state.ID = types.StringValue(uuid.New().String()) + + diags = resp.State.Set(ctx, state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +func isSyncAllUsersNotFoundError(err error) bool { + if envErr, ok := err.(*operations.SyncAllUsersDefault); ok { + if cdp.IsEnvironmentsError(envErr.GetPayload(), "NOT_FOUND", "") { + return true + } + } + return false +} + +func (r *userSyncResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + tflog.Info(ctx, "Nothing to do in read phase") +} + +func (r *userSyncResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var state userSyncResourceModel + diags := req.Plan.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + tflog.Error(ctx, "Got Error while trying to set plan") + return + } + + client := r.client.Environments + + params := operations.NewSyncAllUsersParamsWithContext(ctx) + params.WithInput(toSyncAllUsersRequest(ctx, &state, &resp.Diagnostics)) + _, err := client.Operations.SyncAllUsers(params) + if err != nil { + if isSyncAllUsersNotFoundError(err) { + resp.Diagnostics.AddError( + "Error in sync all users", + "An environment not found: "+state.EnvironmentNames.String(), + ) + return + } + utils.AddEnvironmentDiagnosticsError(err, &resp.Diagnostics, "sync all users") + return + } + + diags = resp.State.Set(ctx, state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *userSyncResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + tflog.Info(ctx, "Nothing to do in delete phase") +} diff --git a/templates/resources/environments_user_sync.md.tmpl b/templates/resources/environments_user_sync.md.tmpl new file mode 100644 index 00000000..c971996d --- /dev/null +++ b/templates/resources/environments_user_sync.md.tmpl @@ -0,0 +1,26 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "{{ index (split .Name "_") 1}}" +description: |- +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +--- + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +{{ if .HasExample -}} +## Example Usage + +{{ tffile .ExampleFile }} +{{- end }} + +{{ .SchemaMarkdown | trimspace }} + +{{- if .HasImport }} +## Import + +Import is supported using the following syntax: + +{{codefile "shell" .ImportFile }} +{{- end }} \ No newline at end of file