From d339247c8b6007326c1c739dfe139532f90ea781 Mon Sep 17 00:00:00 2001 From: saf3dfsa Date: Fri, 10 Jan 2025 17:19:19 +0800 Subject: [PATCH] feat(CodeArts/Deploy): support to deploy app and get deployment records --- ...s_deploy_application_deployment_records.md | 70 +++++ .../codearts_deploy_application_deploy.md | 94 +++++++ huaweicloud/provider.go | 12 +- huaweicloud/services/acceptance/acceptance.go | 11 +- ...loy_application_deployment_records_test.go | 58 +++++ ...codearts_deploy_application_deploy_test.go | 194 ++++++++++++++ ...s_deploy_application_deployment_records.go | 180 +++++++++++++ ...loud_codearts_deploy_application_deploy.go | 245 ++++++++++++++++++ ..._codearts_deploy_application_permission.go | 2 +- ..._codearts_deploy_environment_permission.go | 2 +- ...icloud_codearts_deploy_group_permission.go | 2 +- 11 files changed, 861 insertions(+), 9 deletions(-) create mode 100644 docs/data-sources/codearts_deploy_application_deployment_records.md create mode 100644 docs/resources/codearts_deploy_application_deploy.md create mode 100644 huaweicloud/services/acceptance/codeartsdeploy/data_source_huaweicloud_codearts_deploy_application_deployment_records_test.go create mode 100644 huaweicloud/services/acceptance/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_deploy_test.go create mode 100644 huaweicloud/services/codeartsdeploy/data_source_huaweicloud_codearts_deploy_application_deployment_records.go create mode 100644 huaweicloud/services/codeartsdeploy/resource_hauweicloud_codearts_deploy_application_deploy.go diff --git a/docs/data-sources/codearts_deploy_application_deployment_records.md b/docs/data-sources/codearts_deploy_application_deployment_records.md new file mode 100644 index 0000000000..58f169aefb --- /dev/null +++ b/docs/data-sources/codearts_deploy_application_deployment_records.md @@ -0,0 +1,70 @@ +--- +subcategory: "CodeArts Deploy" +layout: "huaweicloud" +page_title: "HuaweiCloud: huaweicloud_codearts_deploy_application_deployment_records" +description: |- + Use this data source to get the list of CodeArts deploy application deployment records. +--- + +# huaweicloud_codearts_deploy_application_deployment_records + +Use this data source to get the list of CodeArts deploy application deployment records. + +## Example Usage + +```hcl +variable "project_id" {} +variable "task_id" {} +variable "start_date" {} +variable "end_date" {} + +data "huaweicloud_codearts_deploy_application_deployment_records" "test" { + project_id = var.project_id + task_id = var.task_id + start_date = var.start_date + end_date = var.end_date +} +``` + +## 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. + +* `project_id` - (Required, String) Specifies the project ID for CodeArts service. + +* `task_id` - (Required, String) Specifies the deployment task ID. + +* `start_date` - (Required, String) Specifies the start time. The value format is **yyyy-mm-dd**. + +* `end_date` - (Required, String) Specifies the end time. The value format is **yyyy-mm-dd**. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The data source ID. + +* `records` - Indicates the record list. + The [records](#attrblock--records) structure is documented below. + + +The `records` block supports: + +* `id` - Indicates the record ID. + +* `duration` - Indicates the deployment duration. + +* `operator` - Indicates the operator user name. + +* `release_id` - Indicates the deployment record sequence number. + +* `state` - Indicates the application status. + +* `start_time` - Indicates the start time of application deployment. The value format is **yyyy-mm-dd hh:mm:ss**. + +* `end_time` - Indicates the end time of application deployment. The value format is **yyyy-mm-dd hh:mm:ss**. + +* `type` - Indicates the deployment type. diff --git a/docs/resources/codearts_deploy_application_deploy.md b/docs/resources/codearts_deploy_application_deploy.md new file mode 100644 index 0000000000..a354338a23 --- /dev/null +++ b/docs/resources/codearts_deploy_application_deploy.md @@ -0,0 +1,94 @@ +--- +subcategory: "CodeArts Deploy" +layout: "huaweicloud" +page_title: "HuaweiCloud: huaweicloud_codearts_deploy_application_deploy" +description: |- + Manages a CodeArts deploy application deploy resource within HuaweiCloud. +--- + +# huaweicloud_codearts_deploy_application_deploy + +Manages a CodeArts deploy application deploy resource within HuaweiCloud. + +## Example Usage + +```hcl +variable "task_id" {} + +resource "huaweicloud_codearts_deploy_application_deploy" "test" { + task_id = var.task_id +} +``` + +## 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. + +* `task_id` - (Required, String, ForceNew) Specifies the deployment task ID. + Changing this creates a new resource. + +* `params` - (Optional, List, ForceNew) Specifies the parameters transferred during application deployment. + Changing this creates a new resource. + The [params](#block--params) structure is documented below. + +* `record_id` - (Optional, String, ForceNew) Specifies the deployment record ID of an application. Specifies it to roll + back the application to the previous deployment status. + Changing this creates a new resource. + +* `trigger_source` - (Optional, String, ForceNew) Specifies the trigger source. + Valid values are as follows: + + **0**: Deployment can be triggered through all requests. + + **1**: Deployment can be triggered only through pipeline. + + Changing this creates a new resource. + + +The `params` block supports: + +* `name` - (Optional, String, ForceNew) Specifies the parameter name transferred when deploying application. + Changing this creates a new resource. + +* `type` - (Optional, String, ForceNew) Specifies the parameter type. If a dynamic parameter is set, the type is mandatory. + Changing this creates a new resource. + +* `value` - (Optional, String, ForceNew) Specifies the parameter value transferred during application deployment. + Changing this creates a new resource. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The resource ID. + +## Import + +The application deployment record can be imported using `task_id`, and `id`, separated by a slash, e.g. + +```bash +$ terraform import huaweicloud_codearts_deploy_application_deploy.test / +``` + +Please add the followings if some attributes are missing when importing the resource. + +Note that the imported state may not be identical to your resource definition, due to some attributes missing from the +API response, security or some other reason. +The missing attributes include: `params`, `record_id` and `trigger_source`. +It is generally recommended running `terraform plan` after importing the resource. +You can then decide if changes should be applied to the deployment record, or the resource definition should be updated to +align with the deployment record. Also you can ignore changes as below. + +```hcl +resource "huaweicloud_codearts_deploy_application_deploy" "test" { + ... + + lifecycle { + ignore_changes = [ + params, record_id, trigger_source, + ] + } +} +``` diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index dae0fe49b4..0a2a08e88d 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -582,11 +582,12 @@ func Provider() *schema.Provider { "huaweicloud_compute_servergroups": ecs.DataSourceComputeServerGroups(), "huaweicloud_compute_instance_remote_console": ecs.DataSourceComputeInstanceRemoteConsole(), - "huaweicloud_codearts_deploy_groups": codeartsdeploy.DataSourceCodeartsDeployGroups(), - "huaweicloud_codearts_deploy_hosts": codeartsdeploy.DataSourceCodeartsDeployHosts(), - "huaweicloud_codearts_deploy_application_groups": codeartsdeploy.DataSourceCodeartsDeployApplicationGroups(), - "huaweicloud_codearts_deploy_applications": codeartsdeploy.DataSourceCodeartsDeployApplications(), - "huaweicloud_codearts_deploy_environments": codeartsdeploy.DataSourceCodeartsDeployEnvironments(), + "huaweicloud_codearts_deploy_groups": codeartsdeploy.DataSourceCodeartsDeployGroups(), + "huaweicloud_codearts_deploy_hosts": codeartsdeploy.DataSourceCodeartsDeployHosts(), + "huaweicloud_codearts_deploy_application_groups": codeartsdeploy.DataSourceCodeartsDeployApplicationGroups(), + "huaweicloud_codearts_deploy_applications": codeartsdeploy.DataSourceCodeartsDeployApplications(), + "huaweicloud_codearts_deploy_application_deployment_records": codeartsdeploy.DataSourceCodeartsDeployApplicationDeploymentRecords(), + "huaweicloud_codearts_deploy_environments": codeartsdeploy.DataSourceCodeartsDeployEnvironments(), "huaweicloud_cts_notifications": cts.DataSourceNotifications(), "huaweicloud_cts_traces": cts.DataSourceCtsTraces(), @@ -2256,6 +2257,7 @@ func Provider() *schema.Provider { "huaweicloud_codearts_deploy_application": codeartsdeploy.ResourceDeployApplication(), "huaweicloud_codearts_deploy_application_permission": codeartsdeploy.ResourceDeployApplicationPermission(), + "huaweicloud_codearts_deploy_application_deploy": codeartsdeploy.ResourceDeployApplicationDeploy(), "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/acceptance.go b/huaweicloud/services/acceptance/acceptance.go index 1eb04e8d1c..843914410d 100644 --- a/huaweicloud/services/acceptance/acceptance.go +++ b/huaweicloud/services/acceptance/acceptance.go @@ -380,7 +380,9 @@ var ( HW_NEW_GM_ENC_CERTIFICATE_PRIVATE_KEY = os.Getenv("HW_NEW_GM_ENC_CERTIFICATE_PRIVATE_KEY") HW_NEW_GM_CERTIFICATE_CHAIN = os.Getenv("HW_NEW_GM_CERTIFICATE_CHAIN") - HW_CODEARTS_RESOURCE_POOL_ID = os.Getenv("HW_CODEARTS_RESOURCE_POOL_ID") + HW_CODEARTS_RESOURCE_POOL_ID = os.Getenv("HW_CODEARTS_RESOURCE_POOL_ID") + HW_CODEARTS_DEPLOYMENT_TASK_ID = os.Getenv("HW_CODEARTS_DEPLOYMENT_TASK_ID") + HW_CODEARTS_ENABLE_FLAG = os.Getenv("HW_CODEARTS_ENABLE_FLAG") HW_CODEARTS_PUBLIC_IP_ADDRESS = os.Getenv("HW_CODEARTS_PUBLIC_IP_ADDRESS") @@ -1895,6 +1897,13 @@ func TestAccPreCheckCodeArtsDeployResourcePoolID(t *testing.T) { } } +// lintignore:AT003 +func TestAccPreCheckCodeArtsDeploymentTaskID(t *testing.T) { + if HW_CODEARTS_DEPLOYMENT_TASK_ID == "" { + t.Skip("HW_CODEARTS_DEPLOYMENT_TASK_ID must be set for this acceptance test") + } +} + // lintignore:AT003 func TestAccPreCheckCodeArtsEnableFlag(t *testing.T) { if HW_CODEARTS_ENABLE_FLAG == "" { diff --git a/huaweicloud/services/acceptance/codeartsdeploy/data_source_huaweicloud_codearts_deploy_application_deployment_records_test.go b/huaweicloud/services/acceptance/codeartsdeploy/data_source_huaweicloud_codearts_deploy_application_deployment_records_test.go new file mode 100644 index 0000000000..556b34cbfe --- /dev/null +++ b/huaweicloud/services/acceptance/codeartsdeploy/data_source_huaweicloud_codearts_deploy_application_deployment_records_test.go @@ -0,0 +1,58 @@ +package codeartsdeploy + +import ( + "fmt" + "strings" + "testing" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" +) + +func TestAccDataSourceCodeartsDeployApplicationDeploymentRecords_basic(t *testing.T) { + dataSource := "data.huaweicloud_codearts_deploy_application_deployment_records.test" + rName := acceptance.RandomAccResourceName() + dc := acceptance.InitDataSourceCheck(dataSource) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acceptance.TestAccPreCheck(t) + }, + ProviderFactories: acceptance.TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testDataSourceCodeartsDeployApplicationDeploymentRecords_basic(rName), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestCheckResourceAttr(dataSource, "records.#", "1"), + resource.TestCheckResourceAttrSet(dataSource, "records.0.id"), + resource.TestCheckResourceAttrSet(dataSource, "records.0.start_time"), + resource.TestCheckResourceAttrSet(dataSource, "records.0.end_time"), + resource.TestCheckResourceAttrSet(dataSource, "records.0.duration"), + resource.TestCheckResourceAttrSet(dataSource, "records.0.state"), + resource.TestCheckResourceAttrSet(dataSource, "records.0.operator"), + resource.TestCheckResourceAttrSet(dataSource, "records.0.release_id"), + ), + }, + }, + }) +} + +func testDataSourceCodeartsDeployApplicationDeploymentRecords_basic(name string) string { + date := strings.Split(time.Now().Format("2006-01-02T15:04:05Z"), "T")[0] + + return fmt.Sprintf(` +%[1]s + +data "huaweicloud_codearts_deploy_application_deployment_records" "test" { + depends_on = [huaweicloud_codearts_deploy_application_deploy.test] + + project_id = huaweicloud_codearts_project.test.id + task_id = huaweicloud_codearts_deploy_application.test.task_id + start_date = "%[2]s" + end_date = "%[2]s" +} +`, testAccDeployApplicationDeploy_basic(name), date) +} diff --git a/huaweicloud/services/acceptance/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_deploy_test.go b/huaweicloud/services/acceptance/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_deploy_test.go new file mode 100644 index 0000000000..2937d9d9ab --- /dev/null +++ b/huaweicloud/services/acceptance/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_deploy_test.go @@ -0,0 +1,194 @@ +package codeartsdeploy + +import ( + "fmt" + "testing" + "time" + + "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 TestAccDeployApplicationDeploy_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: testAccDeployApplicationDeploy_basic(rName), + Check: resource.ComposeTestCheckFunc( + // wait deployment task become failed, lest the application can not be deleted + func(_ *terraform.State) error { + // lintignore:R018 + time.Sleep(60 * time.Second) + + return nil + }, + ), + }, + }, + }) +} + +//nolint:revive +func testAccDeployApplicationDeploy_basic(name string) string { + return fmt.Sprintf(` +%[1]s + +resource "huaweicloud_codearts_deploy_application" "test" { + project_id = huaweicloud_codearts_project.test.id + name = "%[2]s" + is_draft = false + create_type = "template" + trigger_source = "0" + + operation_list { + name = "Run Shell Commands" + code = "https://wukong-prod-cn-north-4.obs.cn-north-4.myhuaweicloud.com/extensions/devcloud2018/execute_shell_command/1.0.153/roles/main.zip" + entrance = "main.yml" + version = "1.0.153" + module_id = "devcloud2018.execute_shell_command.execute_shell_command" + params = </ +func testDeployApplicationDeployImportState(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) + } + + taskId := rs.Primary.Attributes["task_id"] + if taskId == "" { + return "", fmt.Errorf("attribute (task_id) of resource (%s) not found: %s", name, rs) + } + + return taskId + "/" + rs.Primary.ID, nil + } +} diff --git a/huaweicloud/services/codeartsdeploy/data_source_huaweicloud_codearts_deploy_application_deployment_records.go b/huaweicloud/services/codeartsdeploy/data_source_huaweicloud_codearts_deploy_application_deployment_records.go new file mode 100644 index 0000000000..2e39fc04ca --- /dev/null +++ b/huaweicloud/services/codeartsdeploy/data_source_huaweicloud_codearts_deploy_application_deployment_records.go @@ -0,0 +1,180 @@ +package codeartsdeploy + +import ( + "context" + "fmt" + "strings" + + "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/schema" + + "github.com/chnsz/golangsdk" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils" +) + +// @API CodeArtsDeploy GET /v2/{project_id}/task/{id}/history +func DataSourceCodeartsDeployApplicationDeploymentRecords() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceCodeartsDeployApplicationDeploymentRecordsRead, + + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: `Specifies the region in which to query the resource. If omitted, the provider-level region will be used.`, + }, + "project_id": { + Type: schema.TypeString, + Required: true, + Description: `Specifies the project ID for CodeArts service.`, + }, + "task_id": { + Type: schema.TypeString, + Required: true, + Description: `Specifies the deployment task ID.`, + }, + "start_date": { + Type: schema.TypeString, + Required: true, + Description: `Specifies the start time.`, + }, + "end_date": { + Type: schema.TypeString, + Required: true, + Description: `Specifies the end time.`, + }, + "records": { + Type: schema.TypeList, + Computed: true, + Description: `Indicates the record list.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: `Indicates the record ID.`, + }, + "start_time": { + Type: schema.TypeString, + Computed: true, + Description: `Indicates the start time of application deployment.`, + }, + "end_time": { + Type: schema.TypeString, + Computed: true, + Description: `Indicates the end time of application deployment.`, + }, + "duration": { + Type: schema.TypeString, + Computed: true, + Description: `Indicates the deployment duration.`, + }, + "state": { + Type: schema.TypeString, + Computed: true, + Description: `Indicates the application status.`, + }, + "operator": { + Type: schema.TypeString, + Computed: true, + Description: `Indicates the operator user name.`, + }, + "release_id": { + Type: schema.TypeInt, + Computed: true, + Description: `Indicates the deployment record sequence number.`, + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: `Indicates the deployment type.`, + }, + }, + }, + }, + }, + } +} + +func dataSourceCodeartsDeployApplicationDeploymentRecordsRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cfg := meta.(*config.Config) + region := cfg.GetRegion(d) + client, err := cfg.NewServiceClient("codearts_deploy", region) + if err != nil { + return diag.Errorf("error creating CodeArts deploy client: %s", err) + } + + getHttpUrl := "v2/{project_id}/task/{id}/history" + getPath := client.Endpoint + getHttpUrl + getPath = strings.ReplaceAll(getPath, "{project_id}", d.Get("project_id").(string)) + getPath = strings.ReplaceAll(getPath, "{id}", d.Get("task_id").(string)) + getPath += buildApplicationDeploymentRecordsQueryParams(d) + getOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + MoreHeaders: map[string]string{ + "Content-Type": "application/json;charset=utf-8", + }, + } + + // pageSize is `10` + getPath += fmt.Sprintf("&size=%v", pageSize) + pageIndex := 1 + + rst := make([]map[string]interface{}, 0) + for { + currentPath := getPath + fmt.Sprintf("&page=%d", pageIndex) + getResp, err := client.Request("GET", currentPath, &getOpt) + if err != nil { + return diag.Errorf("error retrieving records: %s", err) + } + getRespBody, err := utils.FlattenResponse(getResp) + if err != nil { + return diag.Errorf("error flatten response: %s", err) + } + + records := utils.PathSearch("result", getRespBody, make([]interface{}, 0)).([]interface{}) + for _, record := range records { + rst = append(rst, map[string]interface{}{ + "id": utils.PathSearch("execution_id", record, nil), + "start_time": utils.PathSearch("start_time", record, nil), + "end_time": utils.PathSearch("end_time", record, nil), + "duration": utils.PathSearch("duration", record, nil), + "state": utils.PathSearch("state", record, nil), + "operator": utils.PathSearch("operator", record, nil), + "release_id": utils.PathSearch("release_id", record, nil), + "type": utils.PathSearch("type", record, nil), + }) + } + + total := utils.PathSearch("total_num", getRespBody, float64(0)).(float64) + if pageSize*(pageIndex-1)+len(records) >= int(total) { + break + } + pageIndex++ + } + + id, err := uuid.GenerateUUID() + if err != nil { + return diag.FromErr(err) + } + d.SetId(id) + + mErr := multierror.Append(nil, + d.Set("region", region), + d.Set("records", rst), + ) + + return diag.FromErr(mErr.ErrorOrNil()) +} + +func buildApplicationDeploymentRecordsQueryParams(d *schema.ResourceData) string { + res := fmt.Sprintf("?start_date=%v", d.Get("start_date")) + res += fmt.Sprintf("&end_date=%v", d.Get("end_date")) + + return res +} diff --git a/huaweicloud/services/codeartsdeploy/resource_hauweicloud_codearts_deploy_application_deploy.go b/huaweicloud/services/codeartsdeploy/resource_hauweicloud_codearts_deploy_application_deploy.go new file mode 100644 index 0000000000..386b5dd3a2 --- /dev/null +++ b/huaweicloud/services/codeartsdeploy/resource_hauweicloud_codearts_deploy_application_deploy.go @@ -0,0 +1,245 @@ +package codeartsdeploy + +import ( + "context" + "fmt" + "strings" + + "github.com/hashicorp/go-multierror" + "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/common" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils" +) + +// @API CodeArtsDeploy POST /v2/tasks/{task_id}/start +// @API CodeArtsDeploy GET /v2/history/tasks/{task_id}/params +func ResourceDeployApplicationDeploy() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceDeployApplicationDeployCreate, + ReadContext: resourceDeployApplicationDeployRead, + DeleteContext: resourceDeployApplicationDeployDelete, + + Importer: &schema.ResourceImporter{ + StateContext: resourceDeployApplicationDeploymentRecordImportState, + }, + + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "task_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `Specifies the deployment task ID.`, + }, + "record_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `Specifies the deployment record ID of an application.`, + }, + "trigger_source": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `Specifies the trigger source.`, + }, + "params": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: `Specifies the parameters transferred during application deployment.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `Specifies the parameter name transferred when deploying application.`, + }, + "value": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `Specifies the parameter value transferred during application deployment.`, + }, + "type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `Specifies the parameter type. If a dynamic parameter is set, the type is mandatory.`, + }, + }, + }, + }, + }, + } +} + +func resourceDeployApplicationDeployCreate(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) + } + + httpUrl := "v2/tasks/{task_id}/start" + createPath := client.Endpoint + httpUrl + createPath = strings.ReplaceAll(createPath, "{task_id}", d.Get("task_id").(string)) + + createOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + MoreHeaders: map[string]string{ + "Content-Type": "application/json;charset=utf-8", + }, + JSONBody: utils.RemoveNil(buildDeployApplicationDeployBodyParams(d)), + } + + createResp, err := client.Request("POST", createPath, &createOpt) + if err != nil { + return diag.Errorf("error deploying CodeArts deploy application: %s", err) + } + + createRespBody, err := utils.FlattenResponse(createResp) + if err != nil { + return diag.FromErr(err) + } + + id := utils.PathSearch("id", createRespBody, "").(string) + if id == "" { + return diag.Errorf("unable to find the deployment record ID from the API response") + } + + d.SetId(id) + + return resourceDeployApplicationDeployRead(ctx, d, meta) +} + +func buildDeployApplicationDeployBodyParams(d *schema.ResourceData) map[string]interface{} { + return map[string]interface{}{ + "record_id": utils.ValueIgnoreEmpty(d.Get("record_id")), + "trigger_source": utils.ValueIgnoreEmpty(d.Get("trigger_source")), + "params": buildDeployApplicationDeployBodyParamsParams(d), + } +} + +func buildDeployApplicationDeployBodyParamsParams(d *schema.ResourceData) []map[string]interface{} { + rawArray := d.Get("params").([]interface{}) + 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{}{ + "key": raw["name"], + "value": raw["value"], + "type": raw["type"], + }) + } + } + + return rst +} + +func resourceDeployApplicationDeployRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cfg := meta.(*config.Config) + region := cfg.GetRegion(d) + client, err := cfg.NewServiceClient("codearts_deploy", region) + if err != nil { + return diag.Errorf("error creating CodeArts deploy client: %s", err) + } + + httpUrl := "v2/history/tasks/{task_id}/params?record_id={record_id}" + getPath := client.Endpoint + httpUrl + getPath = strings.ReplaceAll(getPath, "{task_id}", d.Get("task_id").(string)) + getPath = strings.ReplaceAll(getPath, "{record_id}", d.Id()) + + getOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + MoreHeaders: map[string]string{ + "Content-Type": "application/json;charset=utf-8", + }, + } + + getResp, err := client.Request("GET", getPath, &getOpt) + if err != nil { + return common.CheckDeletedDiag(d, common.ConvertExpected400ErrInto404Err(err, "error_code", "Deploy.00011303"), "") + } + getRespBody, err := utils.FlattenResponse(getResp) + if err != nil { + return diag.FromErr(err) + } + + mErr := multierror.Append(nil, + d.Set("region", region), + d.Set("params", flattenDeploymentRecordExecutionParameters(getRespBody, d)), + ) + + return diag.FromErr(mErr.ErrorOrNil()) +} + +func flattenDeploymentRecordExecutionParameters(respBody interface{}, d *schema.ResourceData) []interface{} { + rawParams := d.Get("params").([]interface{}) + names := make(map[string]bool) + for _, v := range rawParams { + if raw, isMap := v.(map[string]interface{}); isMap { + names[raw["name"].(string)] = true + } + } + + if resp, isList := respBody.([]interface{}); isList { + rst := make([]interface{}, 0, len(names)) + for _, v := range resp { + name := utils.PathSearch("name", v, "").(string) + if !names[name] { + continue + } + rst = append(rst, map[string]interface{}{ + "name": name, + "type": utils.PathSearch("type", v, nil), + "value": utils.PathSearch("value", v, nil), + }) + } + + return rst + } + return nil +} + +func resourceDeployApplicationDeployDelete(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { + errorMsg := "Deleting application deploy resource is not supported. The resource is only removed from the state," + + " the deployment record remains in the cloud." + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Warning, + Summary: errorMsg, + }, + } +} + +func resourceDeployApplicationDeploymentRecordImportState(_ context.Context, d *schema.ResourceData, + _ interface{}) ([]*schema.ResourceData, error) { + parts := strings.Split(d.Id(), "/") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid format specified for import ID, want '/', but got '%s'", + d.Id()) + } + + if err := d.Set("task_id", parts[0]); err != nil { + return nil, fmt.Errorf("error saving task ID: %s", err) + } + d.SetId(parts[1]) + + return []*schema.ResourceData{d}, nil +} diff --git a/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_permission.go b/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_permission.go index 031945f0ad..8f74149d65 100644 --- a/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_permission.go +++ b/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_application_permission.go @@ -132,7 +132,7 @@ func modifyDeployApplicationPermission(client *golangsdk.ServiceClient, d *schem _, err := client.Request("PUT", modifyPath, &modifyOpt) if err != nil { - return fmt.Errorf("error updating CodeArts deploy application permission") + return fmt.Errorf("error updating CodeArts deploy application permission: %s", err) } return nil diff --git a/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_environment_permission.go b/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_environment_permission.go index 3b85e155f7..1a1752ee0e 100644 --- a/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_environment_permission.go +++ b/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_environment_permission.go @@ -105,7 +105,7 @@ func modifyDeployEnvironmentPermission(client *golangsdk.ServiceClient, d *schem _, err := client.Request("PUT", modifyPath, &modifyOpt) if err != nil { - return fmt.Errorf("error modifying CodeArts deploy environment permission") + return fmt.Errorf("error modifying CodeArts deploy environment permission: %s", err) } return nil diff --git a/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_group_permission.go b/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_group_permission.go index 1ddb30ad63..2b4beded3d 100644 --- a/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_group_permission.go +++ b/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_group_permission.go @@ -98,7 +98,7 @@ func modifyDeployGroupPermission(client *golangsdk.ServiceClient, d *schema.Reso _, err := client.Request("PUT", modifyPath, &modifyOpt) if err != nil { - return fmt.Errorf("error modifying CodeArts deploy group permission") + return fmt.Errorf("error modifying CodeArts deploy group permission: %s", err) } return nil