Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ef23436

Browse files
authoredJun 20, 2024
fix(DDS): fix dds backup (#5037)
1 parent cd5aa6f commit ef23436

File tree

2 files changed

+41
-135
lines changed

2 files changed

+41
-135
lines changed
 

Diff for: ‎huaweicloud/services/dds/common.go

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ var (
1313
// Some error codes that need to be retried coming from https://console-intl.huaweicloud.com/apiexplorer/#/errorcenter/DDS.
1414
retryErrCodes = map[string]struct{}{
1515
"DBS.200019": {}, // An operation that conflicts with the current operation is in progress.
16+
"DBS.201014": {},
17+
"DBS.201015": {},
1618
"DBS.239037": {},
1719
"DBS.201000": {}, // ssl
1820
"DBS.00010009": {}, // Instance's status is not available for this operation.

Diff for: ‎huaweicloud/services/dds/resource_huaweicloud_dds_backup.go

+39-135
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,13 @@ import (
1111
"fmt"
1212
"log"
1313
"net/http"
14-
"regexp"
1514
"strings"
1615
"time"
1716

1817
"github.com/hashicorp/go-multierror"
1918
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
2019
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
2120
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
22-
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
2321
"github.com/jmespath/go-jmespath"
2422

2523
"github.com/chnsz/golangsdk"
@@ -70,21 +68,13 @@ func ResourceDdsBackup() *schema.Resource {
7068
Required: true,
7169
ForceNew: true,
7270
Description: `Specifies the manual backup name.`,
73-
ValidateFunc: validation.All(
74-
validation.StringMatch(regexp.MustCompile(`^[A-Za-z-_0-9]*$`),
75-
"the value must be 4 to 64 characters in length and start with a letter"+
76-
"(from A to Z or from a to z). It is case-sensitive and can contain only letters,"+
77-
"digits (from 0 to 9), hyphens (-), and underscores (_)"),
78-
validation.StringLenBetween(4, 64),
79-
),
8071
},
8172
"description": {
82-
Type: schema.TypeString,
83-
Optional: true,
84-
Computed: true,
85-
ForceNew: true,
86-
Description: `Specifies the manual backup description`,
87-
ValidateFunc: validation.StringLenBetween(0, 256),
73+
Type: schema.TypeString,
74+
Optional: true,
75+
Computed: true,
76+
ForceNew: true,
77+
Description: `Specifies the manual backup description`,
8878
},
8979
"instance_name": {
9080
Type: schema.TypeString,
@@ -165,39 +155,29 @@ func resourceDdsBackupCreate(ctx context.Context, d *schema.ResourceData, meta i
165155

166156
createBackupOpt := golangsdk.RequestOpts{
167157
KeepResponseBody: true,
168-
OkCodes: []int{
169-
200,
170-
},
171158
}
172159
createBackupOpt.JSONBody = utils.RemoveNil(buildCreateBackupBodyParams(d))
173160

174-
var createBackupResp *http.Response
175161
instanceId := d.Get("instance_id").(string)
176-
for {
177-
createBackupResp, err = createBackupClient.Request("POST", createBackupPath, &createBackupOpt)
178-
if err == nil {
179-
break
180-
}
181-
// if the HTTP response code is 403 and the error code is DBS.201015 or DBS.201014, then it indicates that other
182-
// operation is being executed and need to wait
183-
if errCode, ok := err.(golangsdk.ErrDefault403); ok {
184-
var backupErr backupError
185-
err = json.Unmarshal(errCode.Body, &backupErr)
186-
if err != nil {
187-
return diag.Errorf("error creating DDS backup: error format error: %s", err)
188-
}
189-
if backupErr.ErrorCode == "DBS.201014" || backupErr.ErrorCode == "DBS.201015" {
190-
err = waitForInstanceRunning(ctx, d, cfg, region, instanceId, schema.TimeoutCreate)
191-
if err != nil {
192-
return diag.FromErr(err)
193-
}
194-
continue
195-
}
196-
}
197-
return diag.Errorf("error creating DDS Backup: %s", err)
162+
retryFunc := func() (interface{}, bool, error) {
163+
resp, err := createBackupClient.Request("POST", createBackupPath, &createBackupOpt)
164+
retry, err := handleMultiOperationsError(err)
165+
return resp, retry, err
166+
}
167+
r, err := common.RetryContextWithWaitForState(&common.RetryContextWithWaitForStateParam{
168+
Ctx: ctx,
169+
RetryFunc: retryFunc,
170+
WaitFunc: ddsInstanceStateRefreshFunc(createBackupClient, instanceId),
171+
WaitTarget: []string{"normal"},
172+
Timeout: d.Timeout(schema.TimeoutCreate),
173+
DelayTimeout: 10 * time.Second,
174+
PollInterval: 10 * time.Second,
175+
})
176+
if err != nil {
177+
return diag.Errorf("error creating DDS backup: %s", err)
198178
}
199179

200-
createBackupRespBody, err := utils.FlattenResponse(createBackupResp)
180+
createBackupRespBody, err := utils.FlattenResponse(r.(*http.Response))
201181
if err != nil {
202182
return diag.FromErr(err)
203183
}
@@ -219,7 +199,7 @@ func resourceDdsBackupCreate(ctx context.Context, d *schema.ResourceData, meta i
219199
Target: []string{"Completed"},
220200
Refresh: ddsJobStatusRefreshFunc(jobId.(string), region, cfg),
221201
Timeout: d.Timeout(schema.TimeoutCreate),
222-
Delay: 60 * time.Second,
202+
Delay: 10 * time.Second,
223203
PollInterval: 10 * time.Second,
224204
}
225205

@@ -243,66 +223,6 @@ func buildCreateBackupBodyParams(d *schema.ResourceData) map[string]interface{}
243223
return params
244224
}
245225

246-
func waitForInstanceRunning(ctx context.Context, d *schema.ResourceData, cfg *config.Config, region, instanceID,
247-
timeout string) error {
248-
stateConf := &resource.StateChangeConf{
249-
Pending: []string{"PENDING"},
250-
Target: []string{"RUNNING"},
251-
Refresh: ddsInstanceStatusRefreshFunc(instanceID, region, cfg),
252-
Timeout: d.Timeout(timeout),
253-
PollInterval: 5 * time.Second,
254-
}
255-
256-
_, err := stateConf.WaitForStateContext(ctx)
257-
if err != nil {
258-
return fmt.Errorf("error waiting for instance (%s) to running: %s", instanceID, err)
259-
}
260-
return nil
261-
}
262-
263-
func ddsInstanceStatusRefreshFunc(instanceId, region string, cfg *config.Config) resource.StateRefreshFunc {
264-
return func() (interface{}, string, error) {
265-
var (
266-
getInstanceHttpUrl = "v3/{project_id}/instances"
267-
getInstanceProduct = "dds"
268-
)
269-
getInstanceClient, err := cfg.NewServiceClient(getInstanceProduct, region)
270-
if err != nil {
271-
return nil, "", fmt.Errorf("error creating DDS client: %s", err)
272-
}
273-
274-
getInstancePath := getInstanceClient.Endpoint + getInstanceHttpUrl
275-
getInstancePath = strings.ReplaceAll(getInstancePath, "{project_id}", getInstanceClient.ProjectID)
276-
277-
getInstancePath += buildGetInstanceQueryParams(instanceId)
278-
getInstanceOpt := golangsdk.RequestOpts{
279-
KeepResponseBody: true,
280-
OkCodes: []int{
281-
200,
282-
},
283-
}
284-
285-
getInstanceResp, err := getInstanceClient.Request("GET", getInstancePath, &getInstanceOpt)
286-
if err != nil {
287-
return nil, "", err
288-
}
289-
290-
getInstanceRespBody, err := utils.FlattenResponse(getInstanceResp)
291-
if err != nil {
292-
return nil, "", err
293-
}
294-
instances := utils.PathSearch("instances", getInstanceRespBody, make([]interface{}, 0))
295-
if len(instances.([]interface{})) == 0 {
296-
return nil, "", fmt.Errorf("can not get instance by instance ID %s", instanceId)
297-
}
298-
actions := utils.PathSearch("actions", instances.([]interface{})[0], make([]interface{}, 0))
299-
if len(actions.([]interface{})) == 0 {
300-
return getInstanceRespBody, "RUNNING", nil
301-
}
302-
return getInstanceRespBody, "PENDING", nil
303-
}
304-
}
305-
306226
func ddsJobStatusRefreshFunc(jobId, region string, cfg *config.Config) resource.StateRefreshFunc {
307227
return func() (interface{}, string, error) {
308228
var (
@@ -322,9 +242,6 @@ func ddsJobStatusRefreshFunc(jobId, region string, cfg *config.Config) resource.
322242

323243
getJobStatusOpt := golangsdk.RequestOpts{
324244
KeepResponseBody: true,
325-
OkCodes: []int{
326-
200,
327-
},
328245
}
329246
getJobStatusResp, err := getJobStatusClient.Request("GET", getJobStatusPath, &getJobStatusOpt)
330247

@@ -385,9 +302,6 @@ func resourceDdsBackupRead(_ context.Context, d *schema.ResourceData, meta inter
385302

386303
getBackupOpt := golangsdk.RequestOpts{
387304
KeepResponseBody: true,
388-
OkCodes: []int{
389-
200,
390-
},
391305
}
392306
getBackupResp, err := getBackupClient.Request("GET", getBackupPath, &getBackupOpt)
393307

@@ -481,38 +395,28 @@ func resourceDdsBackupDelete(ctx context.Context, d *schema.ResourceData, meta i
481395

482396
deleteBackupOpt := golangsdk.RequestOpts{
483397
KeepResponseBody: true,
484-
OkCodes: []int{
485-
200,
486-
},
487398
}
488399

489-
var deleteBackupResp *http.Response
490400
instanceId := d.Get("instance_id").(string)
491-
for {
492-
deleteBackupResp, err = deleteBackupClient.Request("DELETE", deleteBackupPath, &deleteBackupOpt)
493-
if err == nil {
494-
break
495-
}
496-
// if the HTTP response code is 403 and the error code is DBS.201208, then it indicates the backup
497-
// is in the state of backup and need to wait
498-
if errCode, ok := err.(golangsdk.ErrDefault403); ok {
499-
var backupErr backupError
500-
err = json.Unmarshal(errCode.Body, &backupErr)
501-
if err != nil {
502-
return diag.Errorf("error deleting DDS backup: error format error: %s", err)
503-
}
504-
if backupErr.ErrorCode == "DBS.201208" {
505-
err = waitForInstanceRunning(ctx, d, cfg, region, instanceId, schema.TimeoutDelete)
506-
if err != nil {
507-
return diag.FromErr(err)
508-
}
509-
continue
510-
}
511-
}
401+
retryFunc := func() (interface{}, bool, error) {
402+
resp, err := deleteBackupClient.Request("DELETE", deleteBackupPath, &deleteBackupOpt)
403+
retry, err := handleMultiOperationsError(err)
404+
return resp, retry, err
405+
}
406+
r, err := common.RetryContextWithWaitForState(&common.RetryContextWithWaitForStateParam{
407+
Ctx: ctx,
408+
RetryFunc: retryFunc,
409+
WaitFunc: ddsInstanceStateRefreshFunc(deleteBackupClient, instanceId),
410+
WaitTarget: []string{"normal"},
411+
Timeout: d.Timeout(schema.TimeoutCreate),
412+
DelayTimeout: 10 * time.Second,
413+
PollInterval: 10 * time.Second,
414+
})
415+
if err != nil {
512416
return diag.Errorf("error deleting DDS Backup: %s", err)
513417
}
514418

515-
deleteBackupRespBody, err := utils.FlattenResponse(deleteBackupResp)
419+
deleteBackupRespBody, err := utils.FlattenResponse(r.(*http.Response))
516420
if err != nil {
517421
return diag.FromErr(err)
518422
}

0 commit comments

Comments
 (0)
Please sign in to comment.