From ac20094b51370e90a7d93f359a475b4cfb942cf1 Mon Sep 17 00:00:00 2001 From: David Szabo Date: Mon, 29 Apr 2024 08:57:41 +0200 Subject: [PATCH] CDPCP-11832 Resource tfor assigning resource roles to machine users --- provider/provider.go | 3 +- provider/provider_test.go | 3 +- ...l_machine_user_resource_role_assignment.go | 20 +++ ... => model_machine_user_role_assignment.go} | 2 +- ...e_machine_user_resource_role_assignment.go | 128 ++++++++++++++++++ ... resource_machine_user_role_assignment.go} | 29 ++-- ...a_machine_user_resource_role_assignment.go | 35 +++++ ...hine_user_resource_role_assignment_test.go | 64 +++++++++ ...=> schema_machine_user_role_assignment.go} | 2 +- ...hema_machine_user_role_assignment_test.go} | 11 +- 10 files changed, 274 insertions(+), 23 deletions(-) create mode 100644 resources/iam/model_machine_user_resource_role_assignment.go rename resources/iam/{model_assign_machine_user.go => model_machine_user_role_assignment.go} (93%) create mode 100644 resources/iam/resource_machine_user_resource_role_assignment.go rename resources/iam/{resource_assign_machine_user.go => resource_machine_user_role_assignment.go} (72%) create mode 100644 resources/iam/schema_machine_user_resource_role_assignment.go create mode 100644 resources/iam/schema_machine_user_resource_role_assignment_test.go rename resources/iam/{schema_assign_machine_user.go => schema_machine_user_role_assignment.go} (95%) rename resources/iam/{schema_assign_machine_user_test.go => schema_machine_user_role_assignment_test.go} (82%) diff --git a/provider/provider.go b/provider/provider.go index ef7f7475..0c46619e 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -234,7 +234,8 @@ func (p *CdpProvider) Resources(_ context.Context) []func() resource.Resource { datalake.NewAzureDatalakeResource, datalake.NewGcpDatalakeResource, iam.NewGroupResource, - iam.NewAssignMachineUserResource, + iam.NewMachineUserRoleAssignmentResource, + iam.NewMachineUserResourceRoleAssignmentResource, iam.NewMachineUserResource, datahub.NewAwsDatahubResource, datahub.NewAzureDatahubResource, diff --git a/provider/provider_test.go b/provider/provider_test.go index ee72dfe9..bdc8a0f0 100644 --- a/provider/provider_test.go +++ b/provider/provider_test.go @@ -620,8 +620,9 @@ func TestCdpProvider_Resources(t *testing.T) { datalake.NewAzureDatalakeResource, datalake.NewGcpDatalakeResource, iam.NewGroupResource, - iam.NewAssignMachineUserResource, iam.NewMachineUserResource, + iam.NewMachineUserRoleAssignmentResource, + iam.NewMachineUserResourceRoleAssignmentResource, datahub.NewAwsDatahubResource, datahub.NewAzureDatahubResource, datahub.NewGcpDatahubResource, diff --git a/resources/iam/model_machine_user_resource_role_assignment.go b/resources/iam/model_machine_user_resource_role_assignment.go new file mode 100644 index 00000000..56d36cae --- /dev/null +++ b/resources/iam/model_machine_user_resource_role_assignment.go @@ -0,0 +1,20 @@ +// 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 iam + +import "github.com/hashicorp/terraform-plugin-framework/types" + +type machineUserResourceRoleAssignmentResourceModel struct { + Id types.String `tfsdk:"id"` + MachineUser types.String `tfsdk:"machine_user"` + ResourceCrn types.String `tfsdk:"resource_role_crn"` + ResourceRoleCrn types.String `tfsdk:"resource_role_crn"` +} diff --git a/resources/iam/model_assign_machine_user.go b/resources/iam/model_machine_user_role_assignment.go similarity index 93% rename from resources/iam/model_assign_machine_user.go rename to resources/iam/model_machine_user_role_assignment.go index 9901055e..98caba08 100644 --- a/resources/iam/model_assign_machine_user.go +++ b/resources/iam/model_machine_user_role_assignment.go @@ -12,7 +12,7 @@ package iam import "github.com/hashicorp/terraform-plugin-framework/types" -type assignMachineUserResourceModel struct { +type machineUserRoleAssignmentResourceModel struct { Id types.String `tfsdk:"id"` MachineUser types.String `tfsdk:"machine_user"` Role types.String `tfsdk:"role"` diff --git a/resources/iam/resource_machine_user_resource_role_assignment.go b/resources/iam/resource_machine_user_resource_role_assignment.go new file mode 100644 index 00000000..f7e64f03 --- /dev/null +++ b/resources/iam/resource_machine_user_resource_role_assignment.go @@ -0,0 +1,128 @@ +// 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 iam + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-log/tflog" + + "github.com/hashicorp/terraform-plugin-framework/resource" + + "github.com/cloudera/terraform-provider-cdp/cdp-sdk-go/cdp" + "github.com/cloudera/terraform-provider-cdp/cdp-sdk-go/gen/iam/client/operations" + "github.com/cloudera/terraform-provider-cdp/cdp-sdk-go/gen/iam/models" + "github.com/cloudera/terraform-provider-cdp/utils" +) + +var _ resource.Resource = (*machineUserResourceRoleAssignmentResource)(nil) + +func NewMachineUserResourceRoleAssignmentResource() resource.Resource { + return &machineUserResourceRoleAssignmentResource{} +} + +type machineUserResourceRoleAssignmentResource struct { + client *cdp.Client +} + +func (r *machineUserResourceRoleAssignmentResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = MachineUserResourceRoleAssignmentSchema +} + +func (r *machineUserResourceRoleAssignmentResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_machine_user_resource_role_assignment" +} + +func (r *machineUserResourceRoleAssignmentResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data machineUserResourceRoleAssignmentResourceModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + request := operations.NewAssignMachineUserResourceRoleParamsWithContext(ctx).WithInput( + &models.AssignMachineUserResourceRoleRequest{ + MachineUserName: data.MachineUser.ValueStringPointer(), + ResourceCrn: data.ResourceCrn.ValueStringPointer(), + ResourceRoleCrn: data.ResourceRoleCrn.ValueStringPointer(), + }) + + _, err := r.client.Iam.Operations.AssignMachineUserResourceRole(request) // void method, does not have any return value + if err != nil { + utils.AddIamDiagnosticsError(err, &resp.Diagnostics, "assign Machine User Resource Role") + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *machineUserResourceRoleAssignmentResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data machineUserResourceRoleAssignmentResourceModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + params := operations.NewListMachineUserAssignedResourceRolesParamsWithContext(ctx) + params.WithInput(&models.ListMachineUserAssignedResourceRolesRequest{ + MachineUserName: data.MachineUser.ValueStringPointer(), + }) + + machineUser, err := r.client.Iam.Operations.ListMachineUserAssignedResourceRoles(params) + if err != nil { + utils.AddIamDiagnosticsError(err, &resp.Diagnostics, "list Machine User Assigned Resource Roles") + return + } + + hasAssignedResourceRole := false + for _, asgn := range machineUser.Payload.ResourceAssignments { + if asgn.ResourceCrn == data.ResourceCrn.ValueStringPointer() && asgn.ResourceRoleCrn == data.ResourceRoleCrn.ValueStringPointer() { + resp.State.Set(ctx, &data) + hasAssignedResourceRole = true + break + } + } + + if !hasAssignedResourceRole { + resp.Diagnostics.AddError("Resource Role", "Machine User does not have the specified resource role assigned") + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *machineUserResourceRoleAssignmentResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + tflog.Warn(ctx, "Update operation is not supported yet.") +} + +func (r *machineUserResourceRoleAssignmentResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data machineUserResourceRoleAssignmentResourceModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + request := operations.NewUnassignMachineUserResourceRoleParamsWithContext(ctx).WithInput( + &models.UnassignMachineUserResourceRoleRequest{ + MachineUserName: data.MachineUser.ValueStringPointer(), + ResourceCrn: data.ResourceCrn.ValueStringPointer(), + ResourceRoleCrn: data.ResourceRoleCrn.ValueStringPointer(), + }, + ) + + _, err := r.client.Iam.Operations.UnassignMachineUserResourceRole(request) // void method, does not have any return value + if err != nil { + utils.AddIamDiagnosticsError(err, &resp.Diagnostics, "un-assign Machine User Resource Role") + return + } +} diff --git a/resources/iam/resource_assign_machine_user.go b/resources/iam/resource_machine_user_role_assignment.go similarity index 72% rename from resources/iam/resource_assign_machine_user.go rename to resources/iam/resource_machine_user_role_assignment.go index 7e67e392..b77cc28f 100644 --- a/resources/iam/resource_assign_machine_user.go +++ b/resources/iam/resource_machine_user_role_assignment.go @@ -12,6 +12,7 @@ package iam import ( "context" + "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -22,26 +23,26 @@ import ( "github.com/cloudera/terraform-provider-cdp/utils" ) -var _ resource.Resource = (*assignMachineUserResource)(nil) +var _ resource.Resource = (*machineUserRoleAssignmentResource)(nil) -func NewAssignMachineUserResource() resource.Resource { - return &assignMachineUserResource{} +func NewMachineUserRoleAssignmentResource() resource.Resource { + return &machineUserRoleAssignmentResource{} } -type assignMachineUserResource struct { +type machineUserRoleAssignmentResource struct { client *cdp.Client } -func (r *assignMachineUserResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = AssignMachineUserSchema +func (r *machineUserRoleAssignmentResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = MachineUserRoleAssignmentSchema } -func (r *assignMachineUserResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *machineUserRoleAssignmentResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_machine_user_role_assignment" } -func (r *assignMachineUserResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var data assignMachineUserResourceModel +func (r *machineUserRoleAssignmentResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data machineUserRoleAssignmentResourceModel resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) @@ -64,8 +65,8 @@ func (r *assignMachineUserResource) Create(ctx context.Context, req resource.Cre resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func (r *assignMachineUserResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - var data assignMachineUserResourceModel +func (r *machineUserRoleAssignmentResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data machineUserRoleAssignmentResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &data)...) @@ -97,12 +98,12 @@ func (r *assignMachineUserResource) Read(ctx context.Context, req resource.ReadR resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func (r *assignMachineUserResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { +func (r *machineUserRoleAssignmentResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { tflog.Warn(ctx, "Update operation is not supported yet.") } -func (r *assignMachineUserResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - var data assignMachineUserResourceModel +func (r *machineUserRoleAssignmentResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data machineUserRoleAssignmentResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &data)...) diff --git a/resources/iam/schema_machine_user_resource_role_assignment.go b/resources/iam/schema_machine_user_resource_role_assignment.go new file mode 100644 index 00000000..673cac35 --- /dev/null +++ b/resources/iam/schema_machine_user_resource_role_assignment.go @@ -0,0 +1,35 @@ +// 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 iam + +import ( + "github.com/hashicorp/terraform-plugin-framework/resource/schema" +) + +var MachineUserResourceRoleAssignmentSchema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + }, + "machine_user": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The machine user the role is assigned to. Can be the machine user’s name or CRN.", + }, + "resource_crn": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The resource for which the resource role rights are granted.", + }, + "resource_role_crn": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The CRN of the resource role to assign to the machine user.", + }, + }, +} diff --git a/resources/iam/schema_machine_user_resource_role_assignment_test.go b/resources/iam/schema_machine_user_resource_role_assignment_test.go new file mode 100644 index 00000000..d460e09d --- /dev/null +++ b/resources/iam/schema_machine_user_resource_role_assignment_test.go @@ -0,0 +1,64 @@ +// 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 iam + +import ( + "context" + "testing" + + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" +) + +func TestMachineUserResourceRoleAssignmentResourceSchemaContainsExpectedFields(t *testing.T) { + cases := []SchemaTestCaseStructure{ + { + name: "id must exist", + field: "id", + computed: true, + shouldBeRequired: false, + }, + { + name: "machine_user must exist", + field: "machine_user", + computed: false, + shouldBeRequired: true, + }, + { + name: "resource_crn must exist", + field: "resource_crn", + computed: false, + shouldBeRequired: true, + }, + { + name: "resource_role_crn must exist", + field: "resource_role_crn", + computed: false, + shouldBeRequired: true, + }, + } + + underTestAttributes := createFilledMachineUserResourceRoleAssignmentResourceTestObject() + + for _, test := range cases { + t.Run(test.name, func(t *testing.T) { + PerformSchemaValidationForResource(t, test, underTestAttributes[test.field]) + }) + } +} + +func createFilledMachineUserResourceRoleAssignmentResourceTestObject() map[string]schema.Attribute { + res := &machineUserResourceRoleAssignmentResource{} + schemaResponse := &resource.SchemaResponse{} + res.Schema(context.TODO(), resource.SchemaRequest{}, schemaResponse) + + return schemaResponse.Schema.Attributes +} diff --git a/resources/iam/schema_assign_machine_user.go b/resources/iam/schema_machine_user_role_assignment.go similarity index 95% rename from resources/iam/schema_assign_machine_user.go rename to resources/iam/schema_machine_user_role_assignment.go index b48c8193..e9f0ebef 100644 --- a/resources/iam/schema_assign_machine_user.go +++ b/resources/iam/schema_machine_user_role_assignment.go @@ -14,7 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" ) -var AssignMachineUserSchema = schema.Schema{ +var MachineUserRoleAssignmentSchema = schema.Schema{ Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ Computed: true, diff --git a/resources/iam/schema_assign_machine_user_test.go b/resources/iam/schema_machine_user_role_assignment_test.go similarity index 82% rename from resources/iam/schema_assign_machine_user_test.go rename to resources/iam/schema_machine_user_role_assignment_test.go index 850181f6..e1516d8b 100644 --- a/resources/iam/schema_assign_machine_user_test.go +++ b/resources/iam/schema_machine_user_role_assignment_test.go @@ -12,12 +12,13 @@ package iam import ( "context" + "testing" + "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" - "testing" ) -func TestAssignMachineUserResourceSchemaContainsExpectedFields(t *testing.T) { +func TestMachineUserRoleAssignmentResourceSchemaContainsExpectedFields(t *testing.T) { cases := []SchemaTestCaseStructure{ { name: "id must exist", @@ -39,7 +40,7 @@ func TestAssignMachineUserResourceSchemaContainsExpectedFields(t *testing.T) { }, } - underTestAttributes := createFilledAssignMachineUserResourceTestObject() + underTestAttributes := createFilledMachineUserRoleAssignmentResourceTestObject() for _, test := range cases { t.Run(test.name, func(t *testing.T) { @@ -48,8 +49,8 @@ func TestAssignMachineUserResourceSchemaContainsExpectedFields(t *testing.T) { } } -func createFilledAssignMachineUserResourceTestObject() map[string]schema.Attribute { - res := &assignMachineUserResource{} +func createFilledMachineUserRoleAssignmentResourceTestObject() map[string]schema.Attribute { + res := &machineUserRoleAssignmentResource{} schemaResponse := &resource.SchemaResponse{} res.Schema(context.TODO(), resource.SchemaRequest{}, schemaResponse)