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(CodeArts/Deploy): support to deploy app and get deployment records #6181

Merged
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
feat(CodeArts/Deploy): support to deploy app and get deployment records
saf3dfsa committed Jan 20, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit d339247c8b6007326c1c739dfe139532f90ea781
Original file line number Diff line number Diff line change
@@ -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.

<a name="attrblock--records"></a>
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.
94 changes: 94 additions & 0 deletions docs/resources/codearts_deploy_application_deploy.md
Original file line number Diff line number Diff line change
@@ -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.

<a name="block--params"></a>
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 <task_id>/<id>
```

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,
]
}
}
```
12 changes: 7 additions & 5 deletions huaweicloud/provider.go
Original file line number Diff line number Diff line change
@@ -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(),
11 changes: 10 additions & 1 deletion huaweicloud/services/acceptance/acceptance.go
Original file line number Diff line number Diff line change
@@ -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 == "" {
Original file line number Diff line number Diff line change
@@ -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)
}
Original file line number Diff line number Diff line change
@@ -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 = <<EOF
[
{
"name": "groupId",
"label": "Environment",
"displaySettings": {
"DevCloud.ControlType": "DeploymentGroup"
},
"defaultDisplay": [{
"displayName": "",
"value": "",
"host_count": 0,
"os": "linux"
}]
},
{
"name": "shell_command",
"label": "Shell Commands",
"displaySettings": {
"DevCloud.ControlType": "CodeText"
},
"defaultValue": "echo hello"
},
{
"name": "faq_url",
"label": "",
"displaySettings": {
"DevCloud.ControlType": "Hidden"
},
"defaultValue": "/deployman_faq_0030.html"
},
{
"name": "controller_enabled",
"label": "",
"displaySettings": {
"DevCloud.ControlType": "Hidden"
},
"defaultDisplay": [{
"displayName": "Enable this action",
"value": "1"
}]
},
{
"name": "controller_enabled_ignore_errors",
"label": "",
"displaySettings": {
"DevCloud.ControlType": "Checkbox"
},
"defaultDisplay": [{
"displayName": "Keep running on failure",
"value": "0"
}]
},
{
"name": "visibleRule",
"label": "",
"displaySettings": {
"DevCloud.ControlType": "Hidden"
},
"defaultValue": "{\"groupId\":{\"value\":true},\"shell_command\":{\"value\":true},\"faq_url\":{\"value\":true},\"controller_enabled\":{\"value\":true},\"controller_enabled_ignore_errors\":{\"value\":true},\"visibleRule\":{\"value\":true},\"controller_enabled_sudo\":{\"value\":true}}"
},
{
"name": "controller_enabled_sudo",
"label": "",
"displaySettings": {
"DevCloud.ControlType": "Checkbox"
},
"defaultDisplay": [{
"displayName": "Execute this action with the sudo permission",
"value": "0"
}]
}
]
EOF
}
}
resource "huaweicloud_codearts_deploy_application_deploy" "test" {
task_id = huaweicloud_codearts_deploy_application.test.task_id
}
`, testProject_basic(name), name)
}

func TestAccDeployApplicationDeploy_withParams(t *testing.T) {
resourceName := "huaweicloud_codearts_deploy_application_deploy.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acceptance.TestAccPreCheck(t)
acceptance.TestAccPreCheckCodeArtsDeploymentTaskID(t)
},
ProviderFactories: acceptance.TestAccProviderFactories,
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testAccDeployApplicationDeploy_withParams(),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateIdFunc: testDeployApplicationDeployImportState(resourceName),
ImportStateVerifyIgnore: []string{
"params",
},
},
},
})
}

func testAccDeployApplicationDeploy_withParams() string {
return fmt.Sprintf(`
resource "huaweicloud_codearts_deploy_application_deploy" "test" {
task_id = "%s"
params {
name = "name"
value = "value"
type = "enum"
}
}
`, acceptance.HW_CODEARTS_DEPLOYMENT_TASK_ID)
}

// testDeployApplicationDeployImportState use to return an ID with format <task_id>/<id>
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
}
}
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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 '<task_id>/<record_id>', 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
}
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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