From 0a06f845a20bb0fafa02f6d276a711b9d7fa0346 Mon Sep 17 00:00:00 2001 From: luoping-12345 Date: Fri, 20 Dec 2024 10:34:19 +0800 Subject: [PATCH] feat(identitycenter): add resource identitycenter provision permission set --- ...identitycenter_provision_permission_set.md | 56 +++++ huaweicloud/provider.go | 1 + ...itycenter_provision_permission_set_test.go | 55 +++++ ...identitycenter_provision_permission_set.go | 211 ++++++++++++++++++ 4 files changed, 323 insertions(+) create mode 100644 docs/resources/identitycenter_provision_permission_set.md create mode 100644 huaweicloud/services/acceptance/identitycenter/resource_huaweicloud_identitycenter_provision_permission_set_test.go create mode 100644 huaweicloud/services/identitycenter/resource_huaweicloud_identitycenter_provision_permission_set.go diff --git a/docs/resources/identitycenter_provision_permission_set.md b/docs/resources/identitycenter_provision_permission_set.md new file mode 100644 index 00000000000..387e416c1d4 --- /dev/null +++ b/docs/resources/identitycenter_provision_permission_set.md @@ -0,0 +1,56 @@ +--- +subcategory: "IAM Identity Center" +layout: "huaweicloud" +page_title: "HuaweiCloud: huaweicloud_identitycenter_provision_permission_set" +description: |- + Manages an Identity Center provision permission set resource within HuaweiCloud. +--- + +# huaweicloud_identitycenter_provision_permission_set + +Manages an Identity Center provision permission set resource within HuaweiCloud. + +## Example Usage + +```hcl +variable "instance_id" {} +variable "permission_set_id" {} +variable "target_type" {} +variable "target_id" {} + +resource "huaweicloud_identitycenter_provision_permission_set" "test" { + instance_id = var.instance_id + permission_set_id = var.permission_set_id + target_type = var.target_type + target_id = var.target_id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String) Specifies the region in which to query the resource. + If omitted, the provider-level region will be used. + +* `instance_id` - (Required, String, NonUpdatable) Specifies the ID of an IAM Identity Center instance. + +* `permission_set_id` - (Required, String, NonUpdatable) Specifies the ID of a permission set. + +* `target_id` - (Required, String, NonUpdatable) Specifies the account ID. + +* `target_type` - (Required, String, NonUpdatable) Specifies the type of the principal to be attached. + +## Timeouts + +This resource provides the following timeouts configuration options: + +* `create` - Default is 10 minutes. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The resource ID. + +* `status` - The authorization status of a permission set. diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index b16211091a2..61ccb32f2ab 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -1799,6 +1799,7 @@ func Provider() *schema.Provider { "huaweicloud_identitycenter_custom_policy_attachment": identitycenter.ResourceCustomPolicyAttachment(), "huaweicloud_identitycenter_custom_role_attachment": identitycenter.ResourceCustomRoleAttachment(), "huaweicloud_identitycenter_access_control_attribute_configuration": identitycenter.ResourceAccessControlAttributeConfiguration(), + "huaweicloud_identitycenter_provision_permission_set": identitycenter.ResourceProvisionPermissionSet(), "huaweicloud_iec_eip": iec.ResourceEip(), "huaweicloud_iec_keypair": iec.ResourceKeypair(), diff --git a/huaweicloud/services/acceptance/identitycenter/resource_huaweicloud_identitycenter_provision_permission_set_test.go b/huaweicloud/services/acceptance/identitycenter/resource_huaweicloud_identitycenter_provision_permission_set_test.go new file mode 100644 index 00000000000..59f59d6c646 --- /dev/null +++ b/huaweicloud/services/acceptance/identitycenter/resource_huaweicloud_identitycenter_provision_permission_set_test.go @@ -0,0 +1,55 @@ +package identitycenter + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" +) + +func TestAccProvisionPermissionSet_basic(t *testing.T) { + name := acceptance.RandomAccResourceName() + rName := "huaweicloud_identitycenter_provision_permission_set.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acceptance.TestAccPreCheck(t) + acceptance.TestAccPreCheckMultiAccount(t) + }, + ProviderFactories: acceptance.TestAccProviderFactories, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testProvisionPermissionSet_basic(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(rName, "status", "SUCCEEDED"), + ), + }, + }, + }) +} + +func testProvisionPermissionSet_basic(name string) string { + return fmt.Sprintf(` +%[1]s + +resource "huaweicloud_identitycenter_user" "test" { + identity_store_id = data.huaweicloud_identitycenter_instance.test.identity_store_id + user_name = "%[2]s" + password_mode = "OTP" + family_name = "test_family_name" + given_name = "test_given_name" + display_name = "test_display_name" + email = "email@example.com" +} + +resource "huaweicloud_identitycenter_provision_permission_set" "test" { + instance_id = data.huaweicloud_identitycenter_instance.system.id + permission_set_id = huaweicloud_identitycenter_permission_set.test.id + target_id = huaweicloud_identitycenter_user.test.id + target_type = "ACCOUNT" +} +`, testPermissionSet_basic(name), name) +} diff --git a/huaweicloud/services/identitycenter/resource_huaweicloud_identitycenter_provision_permission_set.go b/huaweicloud/services/identitycenter/resource_huaweicloud_identitycenter_provision_permission_set.go new file mode 100644 index 00000000000..619df38e176 --- /dev/null +++ b/huaweicloud/services/identitycenter/resource_huaweicloud_identitycenter_provision_permission_set.go @@ -0,0 +1,211 @@ +package identitycenter + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/chnsz/golangsdk" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils" +) + +var provisionPermissionSetNonUpdatableParams = []string{"instance_id", "permission_set_id", "target_type", "target_id"} + +// @API IdentityCenter POST /v1/instances/{instance_id}/permission-sets/{permission_set_id}/provision +// @API IdentityCenter GET /v1/instances/{instance_id}/permission-sets/provisioning-statuses +func ResourceProvisionPermissionSet() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceProvisionPermissionSetCreate, + UpdateContext: resourceProvisionPermissionSetUpdate, + ReadContext: resourceProvisionPermissionSetRead, + DeleteContext: resourceProvisionPermissionSetDelete, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + }, + + CustomizeDiff: config.FlexibleForceNew(provisionPermissionSetNonUpdatableParams), + + Description: "schema: Internal", + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "instance_id": { + Type: schema.TypeString, + Required: true, + Description: `Specifies the ID of the IAM Identity Center instance.`, + }, + "permission_set_id": { + Type: schema.TypeString, + Required: true, + Description: `Specifies the ID of the IAM Identity Center instance.`, + }, + "target_type": { + Type: schema.TypeString, + Required: true, + Description: `Specifies the type of the principal to be attached.`, + }, + "target_id": { + Type: schema.TypeString, + Required: true, + Description: `Specifies the account ID.`, + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: `The authorization status of a permission set.`, + }, + "enable_force_new": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"true", "false"}, false), + Description: utils.SchemaDesc("", utils.SchemaDescInput{Internal: true}), + }, + }, + } +} + +func resourceProvisionPermissionSetCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cfg := meta.(*config.Config) + region := cfg.GetRegion(d) + instanceId := d.Get("instance_id").(string) + permissionSetId := d.Get("permission_set_id").(string) + // createIdentityCenterProvisionPermissionSet: create IdentityCenter provision permission set + var ( + createProvisionPermissionSetHttpUrl = "v1/instances/{instance_id}/permission-sets/{permission_set_id}/provision" + createProduct = "identitycenter" + ) + client, err := cfg.NewServiceClient(createProduct, region) + if err != nil { + return diag.Errorf("error creating IdentityCenter client: %s", err) + } + + createProvisionPermissionSetPath := client.Endpoint + createProvisionPermissionSetHttpUrl + createProvisionPermissionSetPath = strings.ReplaceAll(createProvisionPermissionSetPath, "{instance_id}", instanceId) + createProvisionPermissionSetPath = strings.ReplaceAll(createProvisionPermissionSetPath, "{permission_set_id}", permissionSetId) + + createProvisionPermissionSetPathOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + } + + createProvisionPermissionSetPathOpt.JSONBody = map[string]interface{}{ + "target_type": d.Get("target_type").(string), + "target_id": d.Get("target_id").(string), + } + + _, err = client.Request("POST", createProvisionPermissionSetPath, &createProvisionPermissionSetPathOpt) + if err != nil { + return diag.Errorf("error creating IdentityCenter provision permission set: %s", err) + } + + err = checkProvisionPermissionSetStatus(ctx, client, instanceId, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return diag.FromErr(err) + } + + uuId, err := uuid.GenerateUUID() + if err != nil { + return diag.Errorf("unable to generate ID: %s", err) + } + d.SetId(uuId) + + return resourceProvisionPermissionSetRead(ctx, d, meta) +} + +func resourceProvisionPermissionSetRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cfg := meta.(*config.Config) + region := cfg.GetRegion(d) + instanceId := d.Get("instance_id").(string) + + client, err := cfg.NewServiceClient("identitycenter", region) + if err != nil { + return diag.Errorf("error creating IdentityCenter client: %s", err) + } + + resp, err := getProvisionPermissionSetStatus(client, instanceId) + if err != nil { + return diag.Errorf("error querying IdentityCenter provision permission set: %s", err) + } + + mErr := multierror.Append( + d.Set("region", region), + d.Set("status", utils.PathSearch("permission_sets_provisioning_status[0].status", resp, nil)), + ) + + return diag.FromErr(mErr.ErrorOrNil()) +} + +func resourceProvisionPermissionSetUpdate(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { + return nil +} + +func resourceProvisionPermissionSetDelete(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { + return nil +} + +func checkProvisionPermissionSetStatus(ctx context.Context, client *golangsdk.ServiceClient, instanceId string, timeout time.Duration) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{"PENDING"}, + Target: []string{"COMPLETED"}, + Refresh: provisionPermissionSetStateRefreshFunc(client, instanceId), + Timeout: timeout, + PollInterval: 10 * timeout, + Delay: 10 * time.Second, + } + _, err := stateConf.WaitForStateContext(ctx) + if err != nil { + return fmt.Errorf("error waiting for IdentityCenter provision permission set to be completed: %s", err) + } + return nil +} + +func provisionPermissionSetStateRefreshFunc(client *golangsdk.ServiceClient, instanceId string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + respBody, err := getProvisionPermissionSetStatus(client, instanceId) + if err != nil { + return nil, "ERROR", err + } + + status := utils.PathSearch("permission_sets_provisioning_status[0].status", respBody, nil).(string) + if status == "SUCCEEDED" { + return respBody, "COMPLETED", nil + } + + if status == "FAILED" { + return respBody, "ERROR", fmt.Errorf("failed to provision IdentityCenter permission set") + } + + return respBody, "PENDING", nil + } +} + +func getProvisionPermissionSetStatus(client *golangsdk.ServiceClient, instanceId string) (interface{}, error) { + getProvisionPermissionSetHttpUrl := "v1/instances/{instance_id}/permission-sets/provisioning-statuses" + getProvisionPermissionSetPath := client.Endpoint + getProvisionPermissionSetHttpUrl + getProvisionPermissionSetPath = strings.ReplaceAll(getProvisionPermissionSetPath, "{instance_id}", instanceId) + + getProvisionPermissionSetPathOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + } + + getProvisionPermissionSetResp, err := client.Request("GET", getProvisionPermissionSetPath, &getProvisionPermissionSetPathOpt) + if err != nil { + return nil, err + } + + return utils.FlattenResponse(getProvisionPermissionSetResp) +}