Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(identitycenter): add resource identitycenter provision permssion set #6067

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions docs/resources/identitycenter_provision_permission_set.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
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 "account_id" {}

resource "huaweicloud_identitycenter_provision_permission_set" "test" {
instance_id = var.instance_id
permission_set_id = var.permission_set_id
account_id = var.account_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.

* `account_id` - (Required, String, NonUpdatable) Specifies the account ID.

## 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.

## Timeouts

This resource provides the following timeouts configuration options:

* `create` - Default is 10 minutes.

## Import

The Identity Center provision permission set can be imported using the `instance_id` and `id`(request ID)
separated by a slash, e.g.

```bash
$ terraform import huaweicloud_identitycenter_provision_permission_set.test <instance_id>/<id>
```
1 change: 1 addition & 0 deletions huaweicloud/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package identitycenter

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"

"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)
acceptance.TestAccPreCheckIdentityCenterAccountId(t)
},
ProviderFactories: acceptance.TestAccProviderFactories,
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testProvisionPermissionSet_basic(name),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(rName, "status", "SUCCEEDED"),
),
},
{
ResourceName: rName,
ImportState: true,
ImportStateIdFunc: testProvisionPermissionSetImportState(rName),
ImportStateVerify: true,
},
},
})
}

func testProvisionPermissionSetImportState(name string) resource.ImportStateIdFunc {
return func(s *terraform.State) (string, error) {
rs, ok := s.RootModule().Resources[name]
if !ok {
return "", fmt.Errorf("resource (%s) not found: %s", name, rs)
}

instanceID := rs.Primary.Attributes["instance_id"]
if instanceID == "" {
return "", fmt.Errorf("attribute (instance_id) of resource (%s) not found: %s", name, rs)
}

return instanceID + "/" + rs.Primary.ID, nil
}
}

func testProvisionPermissionSet_basic(name string) string {
return fmt.Sprintf(`
%[1]s

resource "huaweicloud_identitycenter_provision_permission_set" "test" {
instance_id = data.huaweicloud_identitycenter_instance.test.id
permission_set_id = huaweicloud_identitycenter_permission_set.test.id
account_id = "%[2]s"

depends_on = [huaweicloud_identitycenter_account_assignment.test]
}
`, testAccountAssignment_basic(name), acceptance.HW_IDENTITY_CENTER_ACCOUNT_ID)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
package identitycenter

import (
"context"
"fmt"
"strings"
"time"

"github.com/hashicorp/go-multierror"
"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/common"
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config"
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils"
)

var provisionPermissionSetNonUpdatableParams = []string{"instance_id", "permission_set_id", "account_id"}

// @API IdentityCenter POST /v1/instances/{instance_id}/permission-sets/{permission_set_id}/provision
// @API IdentityCenter GET /v1/instances/{instance_id}/permission-sets/provisioning-status/{request_id}
func ResourceProvisionPermissionSet() *schema.Resource {
return &schema.Resource{
CreateContext: resourceProvisionPermissionSetCreate,
UpdateContext: resourceProvisionPermissionSetUpdate,
ReadContext: resourceProvisionPermissionSetRead,
DeleteContext: resourceProvisionPermissionSetDelete,

Importer: &schema.ResourceImporter{
StateContext: resourceProvisionPermissionSetImport,
},

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 permission set ID of the IAM Identity Center.`,
},
"account_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": "ACCOUNT",
"target_id": d.Get("account_id").(string),
}

resp, err := client.Request("POST", createProvisionPermissionSetPath, &createProvisionPermissionSetPathOpt)
if err != nil {
return diag.Errorf("error creating IdentityCenter provision permission set: %s", err)
}

respBody, err := utils.FlattenResponse(resp)
if err != nil {
return diag.Errorf("error flattening IdentityCenter provision permission set: %s", err)
}

requestId := utils.PathSearch("permission_set_provisioning_status.request_id", respBody, "").(string)
if requestId == "" {
return diag.Errorf("unable to find the request ID from the API response")
}
d.SetId(requestId)

err = checkProvisionPermissionSetStatus(ctx, client, d)
if err != nil {
return diag.FromErr(err)
}

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, d.Id())
if err != nil {
return common.CheckDeletedDiag(d, err, "error querying IdentityCenter provision permission set")
}

mErr := multierror.Append(
d.Set("region", region),
d.Set("permission_set_id", utils.PathSearch("permission_set_provisioning_status.permission_set_id", resp, nil)),
d.Set("account_id", utils.PathSearch("permission_set_provisioning_status.account_id", resp, nil)),
d.Set("status", utils.PathSearch("permission_set_provisioning_status.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 {
errorMsg := "Deleting IdentityCenter provision permission set resource is not supported. The resource is only removed from the state."
return diag.Diagnostics{
diag.Diagnostic{
Severity: diag.Warning,
Summary: errorMsg,
},
}
}

func checkProvisionPermissionSetStatus(ctx context.Context, client *golangsdk.ServiceClient, d *schema.ResourceData) error {
instanceId := d.Get("instance_id").(string)
timeout := d.Timeout(schema.TimeoutCreate)
stateConf := &resource.StateChangeConf{
Pending: []string{"PENDING"},
Target: []string{"COMPLETED"},
Refresh: provisionPermissionSetStateRefreshFunc(client, instanceId, d.Id()),
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, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
respBody, err := getProvisionPermissionSetStatus(client, instanceId, id)
if err != nil {
return nil, "ERROR", err
}

status := utils.PathSearch("permission_set_provisioning_status.status", respBody, "").(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, id string) (interface{}, error) {
getProvisionPermissionSetHttpUrl := "v1/instances/{instance_id}/permission-sets/provisioning-status/{request_id}"
getProvisionPermissionSetPath := client.Endpoint + getProvisionPermissionSetHttpUrl
getProvisionPermissionSetPath = strings.ReplaceAll(getProvisionPermissionSetPath, "{instance_id}", instanceId)
getProvisionPermissionSetPath = strings.ReplaceAll(getProvisionPermissionSetPath, "{request_id}", id)

getProvisionPermissionSetPathOpt := golangsdk.RequestOpts{
KeepResponseBody: true,
}

getProvisionPermissionSetResp, err := client.Request("GET", getProvisionPermissionSetPath, &getProvisionPermissionSetPathOpt)
if err != nil {
return nil, err
}

return utils.FlattenResponse(getProvisionPermissionSetResp)
}

func resourceProvisionPermissionSetImport(_ context.Context, d *schema.ResourceData, _ interface{}) ([]*schema.ResourceData, error) {
parts := strings.Split(d.Id(), "/")
if len(parts) != 2 {
err := fmt.Errorf("invalid format: the format must be <instance_id>/<request_id>")
return nil, err
}

instanceID := parts[0]
requestId := parts[1]

d.Set("instance_id", instanceID)
d.SetId(requestId)

return []*schema.ResourceData{d}, nil
}
Loading