Skip to content

Commit 37c1b8f

Browse files
committed
feat(cph): add resource cph phone data export
1 parent 963992b commit 37c1b8f

File tree

4 files changed

+318
-8
lines changed

4 files changed

+318
-8
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
subcategory: "Cloud Phone (CPH)"
3+
layout: "huaweicloud"
4+
page_title: "HuaweiCloud: huaweicloud_cph_phone_data_export"
5+
description: |-
6+
Manages a CPH phone data export resource within HuaweiCloud.
7+
---
8+
9+
# huaweicloud_cph_phone_data_export
10+
11+
Manages a CPH phone data export resource within HuaweiCloud.
12+
13+
-> The current resource is a one-time resource, and destroying this resource is only removed from the state.
14+
15+
## Example Usage
16+
17+
```hcl
18+
variable "phone_id" {}
19+
variable "bucket_name" {}
20+
variable "object_path" {}
21+
variable "include_files" {}
22+
variable "exclude_files" {}
23+
24+
resource "huaweicloud_cph_phone_data_export" "test" {
25+
phone_id = var.phone_id
26+
bucket_name = var.bucket_name
27+
object_path = var.object_path
28+
include_files = var.include_files
29+
exclude_files = var.exclude_files
30+
}
31+
```
32+
33+
## Argument Reference
34+
35+
The following arguments are supported:
36+
37+
* `region` - (Optional, String, ForceNew) Specifies the region in which to create the resource.
38+
If omitted, the provider-level region will be used.
39+
Changing this creates a new resource.
40+
41+
* `phone_id` - (Required, String) Specifies the phone ID.
42+
43+
* `bucket_name` - (Required, String) Specifies the bucket name of OBS.
44+
45+
* `object_path` - (Required, String) Specifies the object path of OBS.
46+
47+
* `include_files` - (Required, List) Specifies the include files.
48+
49+
* `exclude_files` - (Optional, List) Specifies the exclude files.
50+
51+
## Attribute Reference
52+
53+
In addition to all arguments above, the following attributes are exported:
54+
55+
* `id` - The resource ID.
56+
57+
## Timeouts
58+
59+
This resource provides the following timeouts configuration options:
60+
61+
* `create` - Default is 30 minutes.

huaweicloud/provider.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1560,14 +1560,15 @@ func Provider() *schema.Provider {
15601560
"huaweicloud_coc_script": coc.ResourceScript(),
15611561
"huaweicloud_coc_script_execute": coc.ResourceScriptExecute(),
15621562

1563-
"huaweicloud_cph_server": cph.ResourceCphServer(),
1564-
"huaweicloud_cph_adb_command": cph.ResourceAdbCommand(),
1565-
"huaweicloud_cph_phone_stop": cph.ResourcePhoneStop(),
1566-
"huaweicloud_cph_server_restart": cph.ResourceServerRestart(),
1567-
"huaweicloud_cph_phone_reset": cph.ResourcePhoneReset(),
1568-
"huaweicloud_cph_share_app": cph.ResourceShareApp(),
1569-
"huaweicloud_cph_phone_property": cph.ResourcePhoneProperty(),
1570-
"huaweicloud_cph_phone_restart": cph.ResourcePhoneRestart(),
1563+
"huaweicloud_cph_server": cph.ResourceCphServer(),
1564+
"huaweicloud_cph_adb_command": cph.ResourceAdbCommand(),
1565+
"huaweicloud_cph_phone_stop": cph.ResourcePhoneStop(),
1566+
"huaweicloud_cph_server_restart": cph.ResourceServerRestart(),
1567+
"huaweicloud_cph_phone_reset": cph.ResourcePhoneReset(),
1568+
"huaweicloud_cph_share_app": cph.ResourceShareApp(),
1569+
"huaweicloud_cph_phone_property": cph.ResourcePhoneProperty(),
1570+
"huaweicloud_cph_phone_restart": cph.ResourcePhoneRestart(),
1571+
"huaweicloud_cph_phone_data_export": cph.ResourcePhoneDataExport(),
15711572

15721573
"huaweicloud_cse_microservice": cse.ResourceMicroservice(),
15731574
"huaweicloud_cse_microservice_engine": cse.ResourceMicroserviceEngine(),
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package cph
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8+
9+
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance"
10+
)
11+
12+
func TestAccCphPhoneDataExport_basic(t *testing.T) {
13+
name := acceptance.RandomAccResourceName()
14+
15+
resource.ParallelTest(t, resource.TestCase{
16+
PreCheck: func() {
17+
acceptance.TestAccPreCheck(t)
18+
acceptance.TestAccPrecheckCphObsBucketName(t)
19+
acceptance.TestAccPrecheckCphAdbObjectPath(t)
20+
},
21+
ProviderFactories: acceptance.TestAccProviderFactories,
22+
CheckDestroy: nil,
23+
Steps: []resource.TestStep{
24+
{
25+
Config: testCphPhoneDataExport_basic(name),
26+
},
27+
{
28+
Config: testCphServerBase(name),
29+
Check: resource.ComposeTestCheckFunc(
30+
waitForDeletionCooldownComplete(),
31+
),
32+
},
33+
},
34+
})
35+
}
36+
37+
func testCphPhoneDataExport_basic(name string) string {
38+
return fmt.Sprintf(`
39+
%[1]s
40+
41+
data "huaweicloud_cph_phones" "test" {
42+
server_id = huaweicloud_cph_server.test.id
43+
}
44+
45+
resource "huaweicloud_cph_phone_data_export" "test" {
46+
phone_id = data.huaweicloud_cph_phones.test.phones[0].phone_id
47+
bucket_name = "%[2]s"
48+
object_path = "%[3]s"
49+
include_files = ["/data/app", "/data/local", "/data/media"]
50+
}
51+
`, testCphServer_basic(name), acceptance.HW_CPH_OBS_BUCKET_NAME, acceptance.HW_CPH_OBS_OBJECT_PATH)
52+
}
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package cph
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
"time"
8+
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
12+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
13+
14+
"github.com/chnsz/golangsdk"
15+
16+
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config"
17+
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils"
18+
)
19+
20+
var phoneDataExportNonUpdatableParams = []string{
21+
"phone_id",
22+
"bucket_name",
23+
"object_path",
24+
"include_files",
25+
"exclude_files",
26+
}
27+
28+
// @API CPH POST /v1/{project_id}/cloud-phone/phones/batch-storage
29+
// @API CPH GET /v1/{project_id}/cloud-phone/phones/{phone_id}
30+
func ResourcePhoneDataExport() *schema.Resource {
31+
return &schema.Resource{
32+
CreateContext: resourcePhoneDataExportCreate,
33+
UpdateContext: resourcePhoneDataExportUpdate,
34+
ReadContext: resourcePhoneDataExportRead,
35+
DeleteContext: resourcePhoneDataExportDelete,
36+
37+
Timeouts: &schema.ResourceTimeout{
38+
Create: schema.DefaultTimeout(30 * time.Minute),
39+
},
40+
41+
CustomizeDiff: config.FlexibleForceNew(phoneDataExportNonUpdatableParams),
42+
43+
Schema: map[string]*schema.Schema{
44+
"region": {
45+
Type: schema.TypeString,
46+
Optional: true,
47+
Computed: true,
48+
ForceNew: true,
49+
},
50+
"phone_id": {
51+
Type: schema.TypeString,
52+
Required: true,
53+
Description: `Specifies the phone ID.`,
54+
},
55+
"bucket_name": {
56+
Type: schema.TypeString,
57+
Required: true,
58+
Description: `Specifies the bucket name of OBS.`,
59+
},
60+
"object_path": {
61+
Type: schema.TypeString,
62+
Required: true,
63+
Description: `Specifies the object path of OBS.`,
64+
},
65+
"include_files": {
66+
Type: schema.TypeList,
67+
Required: true,
68+
Elem: &schema.Schema{Type: schema.TypeString},
69+
Description: `Specifies the include files.`,
70+
},
71+
"exclude_files": {
72+
Type: schema.TypeList,
73+
Optional: true,
74+
Elem: &schema.Schema{Type: schema.TypeString},
75+
Description: `Specifies the exclude files.`,
76+
},
77+
"enable_force_new": {
78+
Type: schema.TypeString,
79+
Optional: true,
80+
ValidateFunc: validation.StringInSlice([]string{"true", "false"}, false),
81+
Description: utils.SchemaDesc("", utils.SchemaDescInput{Internal: true}),
82+
},
83+
},
84+
}
85+
}
86+
87+
func resourcePhoneDataExportCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
88+
cfg := meta.(*config.Config)
89+
region := cfg.GetRegion(d)
90+
91+
client, err := cfg.NewServiceClient("cph", region)
92+
if err != nil {
93+
return diag.Errorf("error creating CPH client: %s", err)
94+
}
95+
96+
// createPhoneDataExport: create CPH phone data export
97+
createPhoneDataExportHttpUrl := "v1/{project_id}/cloud-phone/phones/batch-storage"
98+
createPhoneDataExportPath := client.Endpoint + createPhoneDataExportHttpUrl
99+
createPhoneDataExportPath = strings.ReplaceAll(createPhoneDataExportPath, "{project_id}", client.ProjectID)
100+
101+
createPhoneDataExportOpt := golangsdk.RequestOpts{
102+
KeepResponseBody: true,
103+
}
104+
105+
createPhoneDataExportOpt.JSONBody = utils.RemoveNil(map[string]interface{}{
106+
"storage_infos": []map[string]interface{}{
107+
{
108+
"phone_id": d.Get("phone_id"),
109+
"bucket_name": d.Get("bucket_name"),
110+
"object_path": d.Get("object_path"),
111+
"include_files": d.Get("include_files"),
112+
"exclude_files": utils.ValueIgnoreEmpty(d.Get("exclude_files")),
113+
},
114+
},
115+
})
116+
createPhoneDataExportResp, err := client.Request("POST", createPhoneDataExportPath, &createPhoneDataExportOpt)
117+
if err != nil {
118+
return diag.Errorf("error creating CPH phone data export: %s", err)
119+
}
120+
121+
resp, err := utils.FlattenResponse(createPhoneDataExportResp)
122+
if err != nil {
123+
return diag.FromErr(err)
124+
}
125+
id := utils.PathSearch("jobs|[0].phone_id", resp, "").(string)
126+
if id == "" {
127+
return diag.Errorf("unable to find the phone ID from the API response")
128+
}
129+
d.SetId(id)
130+
131+
errorCode := utils.PathSearch("jobs|[0].error_code", resp, "").(string)
132+
if errorCode != "" {
133+
errorMsg := utils.PathSearch("jobs|[0].error_msg", resp, "").(string)
134+
return diag.Errorf("failed to export CPH phone (phone_id: %s) data, error_code: %s, error_msg: %s", id, errorCode, errorMsg)
135+
}
136+
137+
err = checkPhoneDataExportStatus(ctx, client, d.Id(), d.Timeout(schema.TimeoutCreate))
138+
if err != nil {
139+
return diag.FromErr(err)
140+
}
141+
142+
return nil
143+
}
144+
145+
func resourcePhoneDataExportRead(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics {
146+
return nil
147+
}
148+
149+
func resourcePhoneDataExportUpdate(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics {
150+
return nil
151+
}
152+
153+
func resourcePhoneDataExportDelete(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics {
154+
errorMsg := "Deleting CPH phone data export resource is not supported. The resource is only removed from the state."
155+
return diag.Diagnostics{
156+
diag.Diagnostic{
157+
Severity: diag.Warning,
158+
Summary: errorMsg,
159+
},
160+
}
161+
}
162+
163+
func checkPhoneDataExportStatus(ctx context.Context, client *golangsdk.ServiceClient, id string, timeout time.Duration) error {
164+
stateConf := &resource.StateChangeConf{
165+
Pending: []string{"PENDING"},
166+
Target: []string{"COMPLETED"},
167+
Refresh: phoneDataExportStateRefreshFunc(client, id),
168+
Timeout: timeout,
169+
PollInterval: 10 * timeout,
170+
Delay: 10 * time.Second,
171+
}
172+
_, err := stateConf.WaitForStateContext(ctx)
173+
if err != nil {
174+
return fmt.Errorf("error waiting for CPH phone data export to be completed: %s", err)
175+
}
176+
return nil
177+
}
178+
179+
func phoneDataExportStateRefreshFunc(client *golangsdk.ServiceClient, id string) resource.StateRefreshFunc {
180+
return func() (interface{}, string, error) {
181+
getPhoneRespBody, err := getPhoneDetail(client, id)
182+
if err != nil {
183+
return nil, "ERROR", err
184+
}
185+
186+
// Status is 2, indicates the phone is running normally.
187+
phoneStatus := utils.PathSearch("status", getPhoneRespBody, float64(0)).(float64)
188+
if int(phoneStatus) == 2 {
189+
return getPhoneRespBody, "COMPLETED", nil
190+
}
191+
if int(phoneStatus) == -6 {
192+
return getPhoneRespBody, "ERROR", fmt.Errorf("failed to export cloud phone data: %s", id)
193+
}
194+
return getPhoneRespBody, "PENDING", nil
195+
}
196+
}

0 commit comments

Comments
 (0)