diff --git a/docs/resources/codearts_deploy_application.md b/docs/resources/codearts_deploy_application.md index 10dc00cde0..f63d9f7536 100644 --- a/docs/resources/codearts_deploy_application.md +++ b/docs/resources/codearts_deploy_application.md @@ -2,7 +2,8 @@ subcategory: "CodeArts Deploy" layout: "huaweicloud" page_title: "HuaweiCloud: huaweicloud_codearts_deploy_application" -description: "" +description: |- + Manages a CodeArts deploy application resource within HuaweiCloud. --- # huaweicloud_codearts_deploy_application @@ -100,6 +101,9 @@ The following arguments are supported: -> When value is **true**, it's unable to update other parameters. +* `permission_level` - (Optional, String) Specifies the permission level. + Valid values are **instance** and **project**. Defaults to **project**. + The `operation_list` block supports: @@ -139,7 +143,7 @@ In addition to all arguments above, the following attributes are exported: * `can_copy` - Indicates whether the user has the copy permission. -* `can_manage` - Check whether the user has the management permission, including adding, deleting, modifying, +* `can_manage` - Indicates whether the user has the management permission, including adding, deleting, modifying, querying deployment and permission modification. * `can_create_env` - Indicates whether the user has the permission to create an environment. @@ -154,6 +158,35 @@ In addition to all arguments above, the following attributes are exported: * `steps` - The deployment steps. The example value is `{"step1":"XXX", "step2":"XXX"}`. +* `permission_matrix` - Indicates the permission matrix. + The [permission_matrix](#attrblock--permission_matrix) structure is documented below. + + +The `permission_matrix` block supports: + +* `role_id` - Indicates the role ID. + +* `role_name` - Indicates the role name. + +* `role_type` - Indicates the role type. + +* `can_modify` - Indicates whether the role has the editing permission. + +* `can_delete` - Indicates whether the role has the deletion permission. + +* `can_view` - Indicates whether the role has the view permission. + +* `can_execute` - Indicates whether the role has the deployment permission. + +* `can_copy` - Indicates whether the role has the copy permission. + +* `can_manage` - Check whether the role has the management permission, including adding, deleting, modifying, + querying deployment and permission modification. + +* `can_create_env` - Indicates whether the role has the permission to create an environment. + +* `can_disable` - Indicates whether the role has the permission to disable the application. + ## Import The CodeArts deploy application resource can be imported using the `id`, e.g. diff --git a/docs/resources/codearts_deploy_application_permission.md b/docs/resources/codearts_deploy_application_permission.md new file mode 100644 index 0000000000..ce052bc27e --- /dev/null +++ b/docs/resources/codearts_deploy_application_permission.md @@ -0,0 +1,82 @@ +--- +subcategory: "CodeArts Deploy" +layout: "huaweicloud" +page_title: "HuaweiCloud: huaweicloud_codearts_deploy_application_permission" +description: |- + Manages a CodeArts deploy application permission resource within HuaweiCloud. +--- + +# huaweicloud_codearts_deploy_application_permission + +Manages a CodeArts deploy application permission resource within HuaweiCloud. + +-> Only when the applications using instance level permission, this resource is available. + +## Example Usage + +```hcl +variable "project_id" {} +variable "application_ids" {} +variable "role_id" {} + +resource "huaweicloud_codearts_deploy_group_permission" "test" { + project_id = var.project_id + application_ids = var.application_ids + + roles { + role_id = var.role_id + can_modify = true + can_disable = true + can_delete = true + can_view = true + can_execute = true + can_copy = true + can_manage = true + can_create_env = true + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String, ForceNew) Specifies the region in which to create the resource. + If omitted, the provider-level region will be used. + Changing this creates a new resource. + +* `project_id` - (Required, String, ForceNew) Specifies the project ID for CodeArts service. + Changing this creates a new resource. + +* `application_ids` - (Required, List) Specifies the application IDs. + +* `roles` - (Required, List) Specifies the role permissions list. + The [roles](#block--roles) structure is documented below. + + +The `roles` block supports: + +* `role_id` - (Required, String) Specifies the role ID. + +* `can_copy` - (Required, Bool) Specifies whether the role has the copy permission. + +* `can_create_env` - (Required, Bool) Specifies whether the role has the permission to create an environment. + +* `can_delete` - (Required, Bool) Specifies whether the role has the deletion permission. + +* `can_disable` - (Required, Bool) Specifies whether the role has the permission to disable application. + +* `can_execute` - (Required, Bool) Specifies whether the role has the deployment permission. + +* `can_manage` - (Required, Bool) Specifies whether the role has the management permission, including adding, deleting, + modifying, querying deployment and permission modification. + +* `can_modify` - (Required, Bool) Specifies whether the role has the editing permission. + +* `can_view` - (Required, Bool) Specifies whether the role has the view permission. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The resource ID. diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index 1c481e093c..7f5e22e342 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -2253,6 +2253,7 @@ func Provider() *schema.Provider { "huaweicloud_codearts_repository": codearts.ResourceRepository(), "huaweicloud_codearts_deploy_application": codeartsdeploy.ResourceDeployApplication(), + "huaweicloud_codearts_deploy_application_permission": codeartsdeploy.ResourceDeployApplicationPermission(), "huaweicloud_codearts_deploy_application_group": codeartsdeploy.ResourceDeployApplicationGroup(), "huaweicloud_codearts_deploy_application_group_move": codeartsdeploy.ResourceDeployApplicationGroupMove(), "huaweicloud_codearts_deploy_environment": codeartsdeploy.ResourceDeployEnvironment(), diff --git a/huaweicloud/services/acceptance/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_permission_test.go b/huaweicloud/services/acceptance/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_permission_test.go new file mode 100644 index 0000000000..864bdb833c --- /dev/null +++ b/huaweicloud/services/acceptance/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_permission_test.go @@ -0,0 +1,49 @@ +package codeartsdeploy + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" +) + +func TestAccDeployApplicationPermissionModify_basic(t *testing.T) { + rName := acceptance.RandomAccResourceName() + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.TestAccPreCheck(t) }, + ProviderFactories: acceptance.TestAccProviderFactories, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testAccDeployApplicationPermissionModify_basic(rName, false), + }, + { + Config: testAccDeployApplicationPermissionModify_basic(rName, true), + }, + }, + }) +} + +func testAccDeployApplicationPermissionModify_basic(rName string, value bool) string { + return fmt.Sprintf(` +%s + +resource "huaweicloud_codearts_deploy_application_permission" "test" { + project_id = huaweicloud_codearts_deploy_application.test.project_id + application_ids = [huaweicloud_codearts_deploy_application.test.id] + + roles { + role_id = try(huaweicloud_codearts_deploy_application.test.permission_matrix[2].role_id, "") + can_modify = %t + can_disable = true + can_delete = true + can_view = true + can_execute = true + can_copy = true + can_manage = true + can_create_env = true + } +}`, testDeployApplication_basic(rName), value) +} diff --git a/huaweicloud/services/acceptance/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_test.go b/huaweicloud/services/acceptance/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_test.go index 335f43e204..ae3f9d6c2d 100644 --- a/huaweicloud/services/acceptance/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_test.go +++ b/huaweicloud/services/acceptance/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_test.go @@ -76,6 +76,7 @@ func TestAccDeployApplication_basic(t *testing.T) { resource.TestCheckResourceAttr(rName, "trigger_source", "0"), resource.TestCheckResourceAttr(rName, "steps.step1", "Download Package"), resource.TestCheckResourceAttr(rName, "is_disable", "false"), + resource.TestCheckResourceAttr(rName, "permission_level", "instance"), resource.TestCheckResourceAttrSet(rName, "created_at"), resource.TestCheckResourceAttrSet(rName, "updated_at"), resource.TestCheckResourceAttrSet(rName, "project_name"), @@ -105,6 +106,7 @@ func TestAccDeployApplication_basic(t *testing.T) { resource.TestCheckResourceAttr(rName, "trigger_source", "0"), resource.TestCheckResourceAttr(rName, "steps.step1", "Download Package"), resource.TestCheckResourceAttr(rName, "is_disable", "true"), + resource.TestCheckResourceAttr(rName, "permission_level", "project"), resource.TestCheckResourceAttrSet(rName, "created_at"), resource.TestCheckResourceAttrSet(rName, "updated_at"), resource.TestCheckResourceAttrSet(rName, "project_name"), @@ -231,12 +233,13 @@ func testDeployApplication_basic(name string) string { %[1]s resource "huaweicloud_codearts_deploy_application" "test" { - project_id = huaweicloud_codearts_project.test.id - name = "%[2]s" - description = "test description" - is_draft = true - create_type = "template" - trigger_source = "0" + project_id = huaweicloud_codearts_project.test.id + name = "%[2]s" + description = "test description" + is_draft = true + create_type = "template" + trigger_source = "0" + permission_level = "instance" operation_list { name = "Download Package" @@ -279,13 +282,14 @@ func testDeployApplication_update(name string) string { %[1]s resource "huaweicloud_codearts_deploy_application" "test" { - project_id = huaweicloud_codearts_project.test.id - name = "%[2]s-update" - is_draft = false - create_type = "template" - trigger_source = "0" - is_disable = true - group_id = huaweicloud_codearts_deploy_application_group.test.id + project_id = huaweicloud_codearts_project.test.id + name = "%[2]s-update" + is_draft = false + create_type = "template" + trigger_source = "0" + is_disable = true + group_id = huaweicloud_codearts_deploy_application_group.test.id + permission_level = "project" operation_list { name = "Download Package" diff --git a/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_application.go b/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_application.go index 11ed6148cc..a58c825c3b 100644 --- a/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_application.go +++ b/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_application.go @@ -2,12 +2,17 @@ package codeartsdeploy import ( "context" + "encoding/json" "fmt" + "log" "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/jmespath/go-jmespath" "github.com/chnsz/golangsdk" @@ -21,6 +26,8 @@ import ( // @API CodeArtsDeploy PUT /v1/applications // @API CodeArtsDeploy DELETE /v1/applications/{app_id} // @API CodeArtsDeploy PUT /v1/applications/{app_id}/disable +// @API CodeArtsDeploy PUT /v3/applications/permission-level +// @API CodeArtsDeploy GET /v3/applications/permissions // @API CodeArtsDeploy PUT /v1/projects/{project_id}/applications/groups/move func ResourceDeployApplication() *schema.Resource { return &schema.Resource{ @@ -32,6 +39,11 @@ func ResourceDeployApplication() *schema.Resource { StateContext: schema.ImportStatePassthroughContext, }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + }, + // precheck values for `is_draft` and `operation_list`, // when `operation_list` is empty and `is_draft` is true, the application is actually created, // and it's only shown in list API, which means 404 will return when get single application. @@ -126,6 +138,12 @@ func ResourceDeployApplication() *schema.Resource { Optional: true, Description: `Specifies whether to disable the application.`, }, + "permission_level": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: `Specifies the permission level.`, + }, "is_care": { Type: schema.TypeBool, Computed: true, @@ -179,7 +197,7 @@ func ResourceDeployApplication() *schema.Resource { "can_manage": { Type: schema.TypeBool, Computed: true, - Description: `Check whether the user has the management permission, including adding, deleting, + Description: `Indicates whether the user has the management permission, including adding, deleting, modifying, querying deployment and permission modification.`, }, "can_create_env": { @@ -203,6 +221,12 @@ modifying, querying deployment and permission modification.`, Computed: true, Description: `The deployment steps.`, }, + "permission_matrix": { + Type: schema.TypeList, + Elem: deployApplicationPermissionMatrixSchema(), + Computed: true, + Description: `Indicates the permission matrix.`, + }, }, } } @@ -250,6 +274,70 @@ func deployApplicationOperationSchema() *schema.Resource { return &sc } +func deployApplicationPermissionMatrixSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "role_id": { + Type: schema.TypeString, + Computed: true, + Description: `Indicates the role ID.`, + }, + "role_name": { + Type: schema.TypeString, + Computed: true, + Description: `Indicates the role name.`, + }, + "role_type": { + Type: schema.TypeString, + Computed: true, + Description: `Indicates the role type.`, + }, + "can_modify": { + Type: schema.TypeBool, + Computed: true, + Description: `Indicates whether the role has the editing permission.`, + }, + "can_disable": { + Type: schema.TypeBool, + Computed: true, + Description: `Indicates whether the role has the permission to disable application.`, + }, + "can_delete": { + Type: schema.TypeBool, + Computed: true, + Description: `Indicates whether the role has the deletion permission.`, + }, + "can_view": { + Type: schema.TypeBool, + Computed: true, + Description: `Indicates whether the role has the view permission.`, + }, + "can_execute": { + Type: schema.TypeBool, + Computed: true, + Description: `Indicates whether the role has the deployment permission.`, + }, + "can_copy": { + Type: schema.TypeBool, + Computed: true, + Description: `Indicates whether the role has the copy permission.`, + }, + "can_manage": { + Type: schema.TypeBool, + Computed: true, + Description: `Indicates whether the role has the management permission, including adding, deleting, +modifying, querying deployment and permission modification.`, + }, + "can_create_env": { + Type: schema.TypeBool, + Computed: true, + Description: `Indicates whether the role has the permission to create an environment.`, + }, + }, + } + return &sc +} + func resourceDeployApplicationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var ( cfg = meta.(*config.Config) @@ -294,6 +382,13 @@ func resourceDeployApplicationCreate(ctx context.Context, d *schema.ResourceData } } + // `permission_level` defaults to project level when the application is created + if v := d.Get("permission_level").(string); v == "instance" { + if err := updateDeployApplicationPermissionLevel(ctx, client, d, d.Timeout(schema.TimeoutCreate)); err != nil { + return diag.FromErr(err) + } + } + return resourceDeployApplicationRead(ctx, d, meta) } @@ -319,6 +414,39 @@ func updateDeployApplicationDisable(client *golangsdk.ServiceClient, d *schema.R return nil } +func updateDeployApplicationPermissionLevel(ctx context.Context, client *golangsdk.ServiceClient, d *schema.ResourceData, + timeout time.Duration) error { + httpUrl := "v3/applications/permission-level" + updatePath := client.Endpoint + httpUrl + updateOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + JSONBody: map[string]interface{}{ + "project_id": d.Get("project_id"), + "permission_level": d.Get("permission_level"), + "application_ids": []string{d.Id()}, + }, + } + + err := resource.RetryContext(ctx, timeout, func() *resource.RetryError { + _, err := client.Request("PUT", updatePath, &updateOpt) + isRetry, err := handleDeployApplicationPermissionLevelOperationError(err) + if isRetry { + // lintignore:R018 + time.Sleep(10 * time.Second) + return resource.RetryableError(err) + } + if err != nil { + return resource.NonRetryableError(err) + } + return nil + }) + if err != nil { + return fmt.Errorf("error updating CodeArts deploy application permission level: %s", err) + } + + return nil +} + func buildCreateDeployApplicationBodyParams(d *schema.ResourceData) map[string]interface{} { bodyParams := map[string]interface{}{ "project_id": d.Get("project_id"), @@ -438,11 +566,57 @@ func resourceDeployApplicationRead(_ context.Context, d *schema.ResourceData, me d.Set("steps", flattenDeployApplicationSteps(resultRespBody)), d.Set("is_disable", utils.PathSearch("is_disable", resultRespBody, nil)), d.Set("is_care", utils.PathSearch("is_care", resultRespBody, nil)), + d.Set("permission_level", utils.PathSearch("permission_level", resultRespBody, nil)), + ) + + permissionMatrix, err := getDeployApplicationPermissionMatrix(client, d) + if err != nil { + log.Printf("[WARN] failed to retrieve application permission matrix: %s", err) + } + + mErr = multierror.Append( + mErr, + d.Set("permission_matrix", flattenDeployApplicationPermissionMatrix(permissionMatrix)), ) return diag.FromErr(mErr.ErrorOrNil()) } +func getDeployApplicationPermissionMatrix(client *golangsdk.ServiceClient, d *schema.ResourceData) (interface{}, error) { + permissionLevel := d.Get("permission_level").(string) + + httpUrl := "v3/applications/permissions" + getPath := client.Endpoint + httpUrl + if permissionLevel == "instance" { + getPath += fmt.Sprintf("?app_id=%s", d.Id()) + } else { + getPath += fmt.Sprintf("?project_id=%s", d.Get("project_id").(string)) + } + getOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + } + + getResp, err := client.Request("GET", getPath, &getOpt) + if err != nil { + return nil, err + } + getRespBody, err := utils.FlattenResponse(getResp) + if err != nil { + return nil, err + } + + permissionMatrix := utils.PathSearch("result", getRespBody, make([]interface{}, 0)).([]interface{}) + if len(permissionMatrix) == 0 { + return nil, golangsdk.ErrDefault404{ + ErrUnexpectedResponseCode: golangsdk.ErrUnexpectedResponseCode{ + Body: []byte("error retrieving CodeArts deploy application permission matrix, empty list"), + }, + } + } + + return permissionMatrix, nil +} + // flattenDeployApplicationSteps use to flatten deployment steps. // An example of the return value of this function is as follows: '{"step1":"XXX", "step2":"XXX"}' func flattenDeployApplicationSteps(resp interface{}) interface{} { @@ -459,6 +633,30 @@ func flattenDeployApplicationSteps(resp interface{}) interface{} { return rst } +func flattenDeployApplicationPermissionMatrix(respBody interface{}) []interface{} { + if resp, isList := respBody.([]interface{}); isList { + rst := make([]interface{}, 0, len(resp)) + for _, v := range resp { + rst = append(rst, map[string]interface{}{ + "role_id": utils.PathSearch("role_id", v, nil), + "role_name": utils.PathSearch("name", v, nil), + "role_type": utils.PathSearch("role_type", v, nil), + "can_modify": utils.PathSearch("can_modify", v, nil), + "can_disable": utils.PathSearch("can_disable", v, nil), + "can_delete": utils.PathSearch("can_delete", v, nil), + "can_view": utils.PathSearch("can_view", v, nil), + "can_execute": utils.PathSearch("can_execute", v, nil), + "can_copy": utils.PathSearch("can_copy", v, nil), + "can_manage": utils.PathSearch("can_manage", v, nil), + "can_create_env": utils.PathSearch("can_create_env", v, nil), + }) + } + return rst + } + + return nil +} + func resourceDeployApplicationUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { cfg := meta.(*config.Config) region := cfg.GetRegion(d) @@ -502,6 +700,12 @@ func resourceDeployApplicationUpdate(ctx context.Context, d *schema.ResourceData } } + if d.HasChange("permission_level") { + if err := updateDeployApplicationPermissionLevel(ctx, client, d, d.Timeout(schema.TimeoutUpdate)); err != nil { + return diag.FromErr(err) + } + } + if d.HasChange("is_disable") { if err := updateDeployApplicationDisable(client, d); err != nil { return diag.FromErr(err) @@ -583,3 +787,27 @@ func resourceDeployApplicationDelete(_ context.Context, d *schema.ResourceData, return nil } + +// Deploy.00060222: Some application permissions in this project are being updated. Try again later. +// Error will occur when two or more applications using instance level permission are creating. +func handleDeployApplicationPermissionLevelOperationError(err error) (bool, error) { + if err == nil { + return false, nil + } + + if errCode, ok := err.(golangsdk.ErrDefault400); ok { + var apiError interface{} + if jsonErr := json.Unmarshal(errCode.Body, &apiError); jsonErr != nil { + return false, jsonErr + } + + errorCode, errorCodeErr := jmespath.Search("error_code", apiError) + if errorCodeErr != nil { + return false, fmt.Errorf("error parse error code from response body: %s", errorCodeErr) + } + if errorCode == "Deploy.00060222" { + return true, err + } + } + return false, err +} diff --git a/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_permission.go b/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_permission.go new file mode 100644 index 0000000000..031945f0ad --- /dev/null +++ b/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_permission.go @@ -0,0 +1,188 @@ +package codeartsdeploy + +import ( + "context" + "fmt" + + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/chnsz/golangsdk" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" +) + +// @API CodeArtsDeploy PUT /v3/applications/permissions +func ResourceDeployApplicationPermission() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceDeployApplicationPermissionCreateOrUpdate, + ReadContext: resourceDeployApplicationPermissionRead, + UpdateContext: resourceDeployApplicationPermissionCreateOrUpdate, + DeleteContext: resourceDeployApplicationPermissionDelete, + + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "project_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `Specifies the project ID for CodeArts service.`, + }, + "application_ids": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: `Specifies the application IDs.`, + }, + "roles": { + Type: schema.TypeSet, + Required: true, + Description: `Specifies the role permissions list.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "role_id": { + Type: schema.TypeString, + Required: true, + Description: `Specifies the role ID.`, + }, + "can_modify": { + Type: schema.TypeBool, + Required: true, + Description: `Specifies whether the role has the editing permission.`, + }, + "can_disable": { + Type: schema.TypeBool, + Required: true, + Description: `Specifies whether the role has the permission to disable application.`, + }, + "can_delete": { + Type: schema.TypeBool, + Required: true, + Description: `Specifies whether the role has the deletion permission.`, + }, + "can_view": { + Type: schema.TypeBool, + Required: true, + Description: `Specifies whether the role has the view permission.`, + }, + "can_execute": { + Type: schema.TypeBool, + Required: true, + Description: `Specifies whether the role has the deployment permission.`, + }, + "can_copy": { + Type: schema.TypeBool, + Required: true, + Description: `Specifies whether the role has the copy permission.`, + }, + "can_manage": { + Type: schema.TypeBool, + Required: true, + Description: `Specifies whether the role has the management permission, including adding, deleting, + modifying, querying deployment and permission modification.`, + }, + "can_create_env": { + Type: schema.TypeBool, + Required: true, + Description: `Specifies whether the role has the permission to create an environment.`, + }, + }, + }, + }, + }, + } +} + +func resourceDeployApplicationPermissionCreateOrUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cfg := meta.(*config.Config) + client, err := cfg.NewServiceClient("codearts_deploy", cfg.GetRegion(d)) + if err != nil { + return diag.Errorf("error creating CodeArts deploy client: %s", err) + } + + err = modifyDeployApplicationPermission(client, d) + if err != nil { + return diag.FromErr(err) + } + + if d.IsNewResource() { + id, err := uuid.GenerateUUID() + if err != nil { + return diag.FromErr(err) + } + d.SetId(id) + } + + return resourceDeployApplicationPermissionRead(ctx, d, meta) +} + +func modifyDeployApplicationPermission(client *golangsdk.ServiceClient, d *schema.ResourceData) error { + httpUrl := "v3/applications/permissions" + modifyPath := client.Endpoint + httpUrl + modifyOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + JSONBody: buildDeployApplicationPermissionBodyParams(d), + } + + _, err := client.Request("PUT", modifyPath, &modifyOpt) + if err != nil { + return fmt.Errorf("error updating CodeArts deploy application permission") + } + + return nil +} + +func buildDeployApplicationPermissionBodyParams(d *schema.ResourceData) map[string]interface{} { + return map[string]interface{}{ + "project_id": d.Get("project_id"), + "application_ids": d.Get("application_ids").(*schema.Set).List(), + "roles": buildDeployApplicationPermissionBodyParamsRoles(d), + } +} + +func buildDeployApplicationPermissionBodyParamsRoles(d *schema.ResourceData) []map[string]interface{} { + rawArray := d.Get("roles").(*schema.Set).List() + if len(rawArray) == 0 { + return nil + } + + rst := make([]map[string]interface{}, 0, len(rawArray)) + for _, v := range rawArray { + if raw, isMap := v.(map[string]interface{}); isMap { + rst = append(rst, map[string]interface{}{ + "dev_role_id": raw["role_id"], + "can_modify": raw["can_modify"], + "can_disable": raw["can_disable"], + "can_delete": raw["can_delete"], + "can_view": raw["can_view"], + "can_execute": raw["can_execute"], + "can_copy": raw["can_copy"], + "can_manage": raw["can_manage"], + "can_create_env": raw["can_create_env"], + }) + } + } + + return rst +} + +func resourceDeployApplicationPermissionRead(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { + return nil +} + +func resourceDeployApplicationPermissionDelete(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { + errorMsg := "Deleting permission resource is not supported. The resource is only removed from the state," + + " the application permission matrix remains in the cloud." + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Warning, + Summary: errorMsg, + }, + } +}