Skip to content

Commit dd1e1fa

Browse files
authored
Add retry for GET operations with exponential retry (IBM-Cloud#6292)
1 parent 95a3dde commit dd1e1fa

File tree

3 files changed

+115
-39
lines changed

3 files changed

+115
-39
lines changed

ibm/service/iamidentity/resource_ibm_iam_trusted_profile.go

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -189,15 +189,33 @@ func resourceIBMIamTrustedProfileRead(context context.Context, d *schema.Resourc
189189
var trustedProfile *iamidentityv1.TrustedProfile
190190
var response *core.DetailedResponse
191191

192+
var (
193+
initialDelaySec = 2 // seconds
194+
maxDelaySec = 60 // max delay in seconds
195+
196+
)
197+
192198
err = retry.RetryContext(context, 5*time.Minute, func() *retry.RetryError {
193-
trustedProfile, response, err = iamIdentityClient.GetProfileWithContext(context, getProfileOptions)
194-
if err != nil || trustedProfile == nil {
195-
if response != nil && response.StatusCode == 404 {
196-
return retry.RetryableError(err)
199+
retryCount := 0
200+
201+
return func() *retry.RetryError {
202+
// Calculate exponential delay
203+
delaySec := initialDelaySec * (1 << retryCount) // equivalent to initialDelaySec * 2^retryCount
204+
if delaySec > maxDelaySec {
205+
delaySec = maxDelaySec
197206
}
198-
return retry.NonRetryableError(err)
199-
}
200-
return nil
207+
time.Sleep(time.Duration(delaySec) * time.Second)
208+
209+
trustedProfile, response, err = iamIdentityClient.GetProfileWithContext(context, getProfileOptions)
210+
if err != nil || trustedProfile == nil {
211+
retryCount++
212+
if response != nil && response.StatusCode == 404 {
213+
return retry.RetryableError(err)
214+
}
215+
return retry.NonRetryableError(err)
216+
}
217+
return nil
218+
}()
201219
})
202220

203221
if conns.IsResourceTimeoutError(err) {

ibm/service/resourcecontroller/resource_ibm_resource_key.go

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@
44
package resourcecontroller
55

66
import (
7+
"context"
78
"encoding/json"
89
"fmt"
910
"log"
1011
"strconv"
1112
"strings"
1213
"time"
1314

15+
"github.com/IBM/go-sdk-core/v5/core"
1416
rc "github.com/IBM/platform-services-go-sdk/resourcecontrollerv2"
17+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
18+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
1519
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1620

1721
"github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns"
@@ -22,12 +26,12 @@ import (
2226

2327
func ResourceIBMResourceKey() *schema.Resource {
2428
return &schema.Resource{
25-
Create: resourceIBMResourceKeyCreate,
26-
Read: resourceIBMResourceKeyRead,
27-
Update: resourceIBMResourceKeyUpdate,
28-
Delete: resourceIBMResourceKeyDelete,
29-
Exists: resourceIBMResourceKeyExists,
30-
Importer: &schema.ResourceImporter{},
29+
CreateContext: resourceIBMResourceKeyCreate,
30+
ReadContext: resourceIBMResourceKeyRead,
31+
UpdateContext: resourceIBMResourceKeyUpdate,
32+
DeleteContext: resourceIBMResourceKeyDelete,
33+
Exists: resourceIBMResourceKeyExists,
34+
Importer: &schema.ResourceImporter{},
3135

3236
Timeouts: &schema.ResourceTimeout{
3337
Create: schema.DefaultTimeout(10 * time.Minute),
@@ -215,10 +219,10 @@ func ResourceIBMResourceKeyValidator() *validate.ResourceValidator {
215219
return &ibmResourceKeyResourceValidator
216220
}
217221

218-
func resourceIBMResourceKeyCreate(d *schema.ResourceData, meta interface{}) error {
222+
func resourceIBMResourceKeyCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
219223
rsContClient, err := meta.(conns.ClientSession).ResourceControllerV2API()
220224
if err != nil {
221-
return err
225+
return diag.FromErr(err)
222226
}
223227
name := d.Get("name").(string)
224228

@@ -232,7 +236,7 @@ func resourceIBMResourceKeyCreate(d *schema.ResourceData, meta interface{}) erro
232236
}
233237

234238
if instanceID == "" && aliasID == "" {
235-
return fmt.Errorf("[ERROR] Provide either `resource_instance_id` or `resource_alias_id`")
239+
return diag.FromErr(fmt.Errorf("[ERROR] Provide either `resource_instance_id` or `resource_alias_id`"))
236240
}
237241

238242
keyParameters := rc.ResourceKeyPostParameters{}
@@ -251,19 +255,19 @@ func resourceIBMResourceKeyCreate(d *schema.ResourceData, meta interface{}) erro
251255

252256
resourceInstance, sourceCRN, err := getResourceInstanceAndCRN(d, meta)
253257
if err != nil {
254-
return fmt.Errorf("[ERROR] Error creating resource key when get instance and CRN: %s", err)
258+
return diag.FromErr(fmt.Errorf("[ERROR] Error creating resource key when get instance and CRN: %s", err))
255259
}
256260

257261
serviceID := resourceInstance.ResourceID
258262

259263
rsCatClient, err := meta.(conns.ClientSession).ResourceCatalogAPI()
260264
if err != nil {
261-
return fmt.Errorf("[ERROR] Error creating resource key when get ResourceCatalogAPI: %s", err)
265+
return diag.FromErr(fmt.Errorf("[ERROR] Error creating resource key when get ResourceCatalogAPI: %s", err))
262266
}
263267

264268
service, err := rsCatClient.ResourceCatalog().Get(*serviceID, true)
265269
if err != nil {
266-
return fmt.Errorf("[ERROR] Error creating resource key when get service: %s", err)
270+
return diag.FromErr(fmt.Errorf("[ERROR] Error creating resource key when get service: %s", err))
267271
}
268272

269273
resourceKeyCreate := rc.CreateResourceKeyOptions{
@@ -275,7 +279,7 @@ func resourceIBMResourceKeyCreate(d *schema.ResourceData, meta interface{}) erro
275279
role := r.(string)
276280
serviceRole, err := getRoleFromName(role, service.Name, meta)
277281
if err != nil {
278-
return fmt.Errorf("[ERROR] Error creating resource key when get role: %s", err)
282+
return diag.FromErr(fmt.Errorf("[ERROR] Error creating resource key when get role: %s", err))
279283
}
280284
if role != "NONE" {
281285
keyParameters.SetProperty("role_crn", serviceRole.RoleID)
@@ -285,43 +289,80 @@ func resourceIBMResourceKeyCreate(d *schema.ResourceData, meta interface{}) erro
285289

286290
resourceKey, resp, err := rsContClient.CreateResourceKey(&resourceKeyCreate)
287291
if err != nil {
288-
return fmt.Errorf("[ERROR] Error creating resource key: %s with resp code: %s", err, resp)
292+
return diag.FromErr(fmt.Errorf("[ERROR] Error creating resource key: %s with resp code: %s", err, resp))
289293
}
290294

291295
d.SetId(*resourceKey.ID)
292296

293-
return resourceIBMResourceKeyRead(d, meta)
297+
return resourceIBMResourceKeyRead(context, d, meta)
294298
}
295299

296-
func resourceIBMResourceKeyUpdate(d *schema.ResourceData, meta interface{}) error {
300+
func resourceIBMResourceKeyUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
297301
return nil
298302
}
299303

300-
func resourceIBMResourceKeyRead(d *schema.ResourceData, meta interface{}) error {
304+
func resourceIBMResourceKeyRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
301305
rsContClient, err := meta.(conns.ClientSession).ResourceControllerV2API()
302306
if err != nil {
303-
return err
307+
return diag.FromErr(err)
304308
}
305309
resourceKeyID := d.Id()
306310
resourceKeyGet := rc.GetResourceKeyOptions{
307311
ID: &resourceKeyID,
308312
}
309313

310-
resourceKey, resp, err := rsContClient.GetResourceKey(&resourceKeyGet)
314+
var resp *core.DetailedResponse
315+
var resourceKey *rc.ResourceKey
316+
var (
317+
initialDelaySec = 2 // seconds
318+
maxDelaySec = 60 // max delay in seconds
319+
320+
)
321+
322+
err = retry.RetryContext(context, 5*time.Minute, func() *retry.RetryError {
323+
retryCount := 0
324+
325+
return func() *retry.RetryError {
326+
// Calculate exponential delay
327+
delaySec := initialDelaySec * (1 << retryCount) // equivalent to initialDelaySec * 2^retryCount
328+
if delaySec > maxDelaySec {
329+
delaySec = maxDelaySec
330+
}
331+
time.Sleep(time.Duration(delaySec) * time.Second)
332+
333+
resourceKey, resp, err = rsContClient.GetResourceKey(&resourceKeyGet)
334+
if err != nil || resourceKey == nil {
335+
retryCount++
336+
if resp != nil && resp.StatusCode == 404 {
337+
return retry.RetryableError(err)
338+
}
339+
return retry.NonRetryableError(err)
340+
}
341+
return nil
342+
}()
343+
})
344+
if conns.IsResourceTimeoutError(err) {
345+
resourceKey, resp, err = rsContClient.GetResourceKey(&resourceKeyGet)
346+
}
311347
if err != nil || resourceKey == nil {
312-
return fmt.Errorf("[ERROR] Error retrieving resource key: %s with resp : %s", err, resp)
348+
if resp != nil && resp.StatusCode == 404 {
349+
d.SetId("")
350+
return nil
351+
}
352+
return diag.FromErr(fmt.Errorf("[ERROR] Error retrieving resource key: %s with resp : %s", err, resp))
313353
}
354+
314355
var credInterface map[string]interface{}
315356
cred, _ := json.Marshal(resourceKey.Credentials)
316357
json.Unmarshal(cred, &credInterface)
317358
d.Set("credentials", flex.Flatten(credInterface))
318359

319360
creds, err := json.Marshal(resourceKey.Credentials)
320361
if err != nil {
321-
return fmt.Errorf("[ERROR] Error marshalling resource key credentials: %s", err)
362+
return diag.FromErr(fmt.Errorf("[ERROR] Error marshalling resource key credentials: %s", err))
322363
}
323364
if err = d.Set("credentials_json", string(creds)); err != nil {
324-
return fmt.Errorf("[ERROR] Error setting the credentials json: %s", err)
365+
return diag.FromErr(fmt.Errorf("[ERROR] Error setting the credentials json: %s", err))
325366
}
326367
d.Set("name", *resourceKey.Name)
327368
d.Set("status", *resourceKey.State)
@@ -398,10 +439,10 @@ func resourceIBMResourceKeyRead(d *schema.ResourceData, meta interface{}) error
398439
return nil
399440
}
400441

401-
func resourceIBMResourceKeyDelete(d *schema.ResourceData, meta interface{}) error {
442+
func resourceIBMResourceKeyDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
402443
rsContClient, err := meta.(conns.ClientSession).ResourceControllerV2API()
403444
if err != nil {
404-
return err
445+
return diag.FromErr(err)
405446
}
406447

407448
resourceKeyID := d.Id()
@@ -411,7 +452,7 @@ func resourceIBMResourceKeyDelete(d *schema.ResourceData, meta interface{}) erro
411452

412453
resp, err := rsContClient.DeleteResourceKey(&resourceKeyDelete)
413454
if err != nil {
414-
return fmt.Errorf("[ERROR] Error deleting resource key: %s with resp code: %s", err, resp)
455+
return diag.FromErr(fmt.Errorf("[ERROR] Error deleting resource key: %s with resp code: %s", err, resp))
415456
}
416457

417458
d.SetId("")

ibm/service/resourcemanager/resource_ibm_resource_group.go

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,16 +140,33 @@ func resourceIBMResourceGroupRead(context context.Context, d *schema.ResourceDat
140140

141141
var resp *core.DetailedResponse
142142
var resourceGroup *rg.ResourceGroup
143+
var (
144+
initialDelaySec = 2 // seconds
145+
maxDelaySec = 60 // max delay in seconds
146+
147+
)
143148

144149
err = retry.RetryContext(context, 5*time.Minute, func() *retry.RetryError {
145-
resourceGroup, resp, err = rMgtClient.GetResourceGroup(&resourceGroupGet)
146-
if err != nil || resourceGroup == nil {
147-
if resp != nil && resp.StatusCode == 404 {
148-
return retry.RetryableError(err)
150+
retryCount := 0
151+
152+
return func() *retry.RetryError {
153+
// Calculate exponential delay
154+
delaySec := initialDelaySec * (1 << retryCount) // equivalent to initialDelaySec * 2^retryCount
155+
if delaySec > maxDelaySec {
156+
delaySec = maxDelaySec
149157
}
150-
return retry.NonRetryableError(err)
151-
}
152-
return nil
158+
time.Sleep(time.Duration(delaySec) * time.Second)
159+
160+
resourceGroup, resp, err = rMgtClient.GetResourceGroup(&resourceGroupGet)
161+
if err != nil || resourceGroup == nil {
162+
retryCount++
163+
if resp != nil && resp.StatusCode == 404 {
164+
return retry.RetryableError(err)
165+
}
166+
return retry.NonRetryableError(err)
167+
}
168+
return nil
169+
}()
153170
})
154171

155172
if conns.IsResourceTimeoutError(err) {

0 commit comments

Comments
 (0)